feat(realism): wire fingerprint_html/svg through taxonomy + UI
The two new fingerprint canary generators existed at the API level
since f64e78f but weren't visible to the realism engine or the
operator-facing dashboard. Threads them through every place that
enumerates canary content classes.
Backend:
* realism/taxonomy.py - two new ContentClass members
(CANARY_FINGERPRINT_HTML, CANARY_FINGERPRINT_SVG); enum is
wire-visible (synthetic_files.content_class column + bus discrim)
so we add at the bottom, never reorder.
* canary/cultivator.py - class-to-generator dispatch, kind mapping
(both http), and default placement paths
(~/Documents/asset_directory.html and network_topology.svg).
* realism/naming.py + bodies.py - _name_canary / _body_canary entries.
* realism/planner.py - added to _DEFAULT_CANARY_CLASS_WEIGHTS and
the _CANARY_CLASSES classification set.
Frontend:
* decnet_web/src/realism/labels.ts - display labels.
* decnet_web/src/components/RealismConfig/RealismConfig.tsx - default
canary weight rows so operators see them in the realism config UI.
* decnet_web/src/components/SyntheticFiles/SyntheticFiles.tsx - added
to the CONTENT_CLASSES allow-list so filter dropdowns show them.
Also: re-applied the nosec B404/B603 markers on canary/obfuscator.py;
the first commit's pre-commit autoformatter stripped them.
Tests: extended tests/realism/test_taxonomy.py's stability assertion
to include the two new values. Full canary + realism suites pass
(362 / 2 skipped).
This commit is contained in:
@@ -213,6 +213,8 @@ _BODIES: dict[ContentClass, Callable[[str, secrets.SystemRandom], str]] = {
|
||||
ContentClass.CANARY_HONEYDOC_DOCX: _body_canary,
|
||||
ContentClass.CANARY_HONEYDOC_PDF: _body_canary,
|
||||
ContentClass.CANARY_MYSQL_DUMP: _body_canary,
|
||||
ContentClass.CANARY_FINGERPRINT_HTML: _body_canary,
|
||||
ContentClass.CANARY_FINGERPRINT_SVG: _body_canary,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -159,6 +159,8 @@ _NAMERS: dict[ContentClass, Callable[[str, secrets.SystemRandom], str]] = {
|
||||
ContentClass.CANARY_HONEYDOC_DOCX: _name_canary,
|
||||
ContentClass.CANARY_HONEYDOC_PDF: _name_canary,
|
||||
ContentClass.CANARY_MYSQL_DUMP: _name_canary,
|
||||
ContentClass.CANARY_FINGERPRINT_HTML: _name_canary,
|
||||
ContentClass.CANARY_FINGERPRINT_SVG: _name_canary,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ _DEFAULT_CANARY_CLASS_WEIGHTS: tuple[tuple[ContentClass, int], ...] = (
|
||||
(ContentClass.CANARY_HONEYDOC_DOCX, 1),
|
||||
(ContentClass.CANARY_HONEYDOC_PDF, 1),
|
||||
(ContentClass.CANARY_MYSQL_DUMP, 1),
|
||||
(ContentClass.CANARY_FINGERPRINT_HTML, 1),
|
||||
(ContentClass.CANARY_FINGERPRINT_SVG, 1),
|
||||
)
|
||||
_DEFAULT_CANARY_PROBABILITY = 0.03
|
||||
|
||||
@@ -134,6 +136,7 @@ _CANARY_CLASSES: set[ContentClass] = {
|
||||
ContentClass.CANARY_GIT_CONFIG, ContentClass.CANARY_SSH_KEY,
|
||||
ContentClass.CANARY_HONEYDOC, ContentClass.CANARY_HONEYDOC_DOCX,
|
||||
ContentClass.CANARY_HONEYDOC_PDF, ContentClass.CANARY_MYSQL_DUMP,
|
||||
ContentClass.CANARY_FINGERPRINT_HTML, ContentClass.CANARY_FINGERPRINT_SVG,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ class ContentClass(StrEnum):
|
||||
CANARY_HONEYDOC_DOCX = "canary_honeydoc_docx"
|
||||
CANARY_HONEYDOC_PDF = "canary_honeydoc_pdf"
|
||||
CANARY_MYSQL_DUMP = "canary_mysql_dump"
|
||||
CANARY_FINGERPRINT_HTML = "canary_fingerprint_html"
|
||||
CANARY_FINGERPRINT_SVG = "canary_fingerprint_svg"
|
||||
|
||||
def is_canary(self) -> bool:
|
||||
return self.value.startswith("canary_")
|
||||
|
||||
Reference in New Issue
Block a user