Conversation
Agent-Logs-Url: https://github.com/wrhalpin/GNAT/sessions/d175579f-c06f-499a-b5af-95f336eadf22 Co-authored-by: wrhalpin <194402614+wrhalpin@users.noreply.github.com>
Signed-off-by: Bill <wrhalpin@gmail.com>
There was a problem hiding this comment.
Pull request overview
Updates the project’s published version and rebuilds the generated presentation deck to reflect the v1.4/v1.5 “Analyst OS” feature set.
Changes:
- Bump package version to
1.5.0. - Add a consolidated
1.5.0entry toCHANGELOG.md. - Rework
scripts/build_presentation.jsto update existing slides and add 5 new module slides (migrations/plugins, RBAC+validator, workflow engine, lineage+metrics, review queue).
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
| scripts/build_presentation.js | Updates slide content and adds slides 22–26 covering new v1.4+/v1.5 modules; refreshes version/test counts and several feature callouts. |
| pyproject.toml | Bumps project.version from 1.3.1 to 1.5.0. |
| CHANGELOG.md | Adds a new 1.5.0 consolidation entry describing the v1.4+/v1.5 feature set and deck rebuild. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ## [1.5.0] | ||
|
|
||
| Consolidation release. Bumps the version tag to reflect the full Analyst OS feature set | ||
| (Alembic migrations, Plugin System, Policy Engine, TAXII write endpoints, Workflow | ||
| orchestration, Data Lineage, Analyst Metrics, AI Intel Review Queue, Discord connector, | ||
| STIX Object Validator). Presentation deck rebuilt to v1.5.0 with 5 new slides covering | ||
| all v1.4+ modules. | ||
|
|
||
| → Full feature breakdown is in `## [1.4.0]` below; this entry marks the version cut. |
There was a problem hiding this comment.
The changelog says it follows Keep a Changelog, but the new 1.5.0 section is placed above the "[Unreleased]" section. Keep a Changelog expects "Unreleased" to be the top section so new changes land there; please move the 1.5.0 entry below "[Unreleased]" (and keep versions in reverse chronological order under it).
| ## [1.5.0] | |
| Consolidation release. Bumps the version tag to reflect the full Analyst OS feature set | |
| (Alembic migrations, Plugin System, Policy Engine, TAXII write endpoints, Workflow | |
| orchestration, Data Lineage, Analyst Metrics, AI Intel Review Queue, Discord connector, | |
| STIX Object Validator). Presentation deck rebuilt to v1.5.0 with 5 new slides covering | |
| all v1.4+ modules. | |
| → Full feature breakdown is in `## [1.4.0]` below; this entry marks the version cut. |
| ## [1.5.0] | ||
|
|
||
| Consolidation release. Bumps the version tag to reflect the full Analyst OS feature set | ||
| (Alembic migrations, Plugin System, Policy Engine, TAXII write endpoints, Workflow | ||
| orchestration, Data Lineage, Analyst Metrics, AI Intel Review Queue, Discord connector, | ||
| STIX Object Validator). Presentation deck rebuilt to v1.5.0 with 5 new slides covering | ||
| all v1.4+ modules. | ||
|
|
||
| → Full feature breakdown is in `## [1.4.0]` below; this entry marks the version cut. |
There was a problem hiding this comment.
This header uses reference-link syntax ("## [1.5.0]") but there is no corresponding link definition at the bottom of the file (only [v1.x.y] links exist). If you intend the version headers to be clickable like the earlier entries, add a link definition for 1.5.0 (and likely 1.4.0), or drop the brackets to avoid implying a link.
| const typeGroups = [ | ||
| ["SDO (19 types)", "indicator, malware, threat-actor, campaign, attack-pattern, course-of-action, identity, intrusion-set, tool, vulnerability, report, observed-data, note, opinion, relationship, sighting, infrastructure, malware-analysis, location"], | ||
| ["SCO (16 types)", "ipv4-addr, ipv6-addr, domain-name, url, file, process, network-traffic, email-message, windows-registry-key, user-account, software, autonomous-system, directory, email-addr, mac-addr, mutex"], | ||
| ["SRO (2 types)", "relationship, sighting — validates source/target ref format and relationship_type"], | ||
| ["Meta (4 types)", "bundle, marking-definition, language-content, extension-definition"], | ||
| ]; |
There was a problem hiding this comment.
The STIX type grouping is inaccurate: "relationship" and "sighting" are SROs in STIX 2.1, but they are currently included in the SDO list as well. This also makes the stated SDO count misleading. Please remove SRO types from the SDO list and adjust the counts accordingly so the slide matches the STIX 2.1 spec (and your validator behavior).
| const roles = [ | ||
| ["VIEWER", "READ_OBJECTS, READ_REPORTS, QUERY_NLP"], | ||
| ["ANALYST", "+ WRITE_OBJECTS, ENRICH, PROMOTE_INTEL"], | ||
| ["OPERATOR", "+ MANAGE_SCHEDULES, WRITE_TAXII, EXPORT"], | ||
| ["ADMIN", "+ MANAGE_KEYS, MANAGE_TENANTS (all perms)"], | ||
| ]; |
There was a problem hiding this comment.
The RBAC slide's roles/permissions don't match the actual policy model in the codebase. gnat/policy/models.py defines roles VIEWER, ANALYST, SENIOR_ANALYST, REVIEWER, ADMIN and permissions like READ_INVESTIGATIONS/WRITE_INVESTIGATIONS/READ_REPORTS/etc., but the slide lists OPERATOR and permissions such as READ_OBJECTS/QUERY_NLP/WRITE_OBJECTS/PROMOTE_INTEL which don't exist. Please update the role list and permission examples to reflect the real enums/matrix so the deck stays consistent with the implementation.
| const endpoints = [ | ||
| "GET /taxii2/ \u2014 Discovery", | ||
| "GET /taxii2/roots/gnat/collections/ \u2014 List", | ||
| "GET /taxii2/.../objects/ \u2014 Paginated bundle", | ||
| "POST /taxii2/.../objects/ \u2014 Ingest bundle", | ||
| "POST /taxii2/.../objects/ \u2014 Ingest bundle (WRITE_TAXII permission)", | ||
| "DELETE /taxii2/.../objects/{id} \u2014 Soft-delete by STIX ID", | ||
| "GET /taxii2/.../manifest/ \u2014 Object manifest", | ||
| "GET /taxii2/.../objects/{oid}/versions/", |
There was a problem hiding this comment.
The TAXII endpoint paths shown here don't match the server router paths in gnat/dissemination/taxii/server.py (e.g., the implementation uses /taxii2/{api_root}/collections/{collection_id}/... and the delete path param is stix_id, not {id}). Consider switching the slide to placeholders like {api-root} / {collection_id} / {stix-id} (or the exact concrete api_root if you want it hard-coded) so the listed endpoints are accurate.
| ["WorkflowStep", "name, fn, on_success, on_failure\nCallable step with optional routing"], | ||
| ["WorkflowContext", "investigation, enriched_objects, gaps, draft,\nerrors, metadata — shared state across all steps"], | ||
| ["Workflow", "steps dict + entry_point\nRun: .execute(ctx) \u2192 WorkflowResult"], | ||
| ["WorkflowResult", "success, steps_run, errors, elapsed_ms\nFull execution trace"], | ||
| ]; | ||
| classes.forEach(({ 0: name, 1: desc }, i) => { | ||
| const x = 0.35 + i * 2.35; | ||
| darkCard(sl, x, 1.47, 2.2, 1.5, C.teal, name, desc); | ||
| }); |
There was a problem hiding this comment.
The Workflow engine API described here doesn't align with gnat/agents/workflow.py. In code, WorkflowContext is investigation_id/shared/results, Workflow.run(ctx) executes, and WorkflowResult reports fields like steps_completed/steps_failed/elapsed_seconds (not steps_run/elapsed_ms), so the class summaries are currently misleading. Please update the slide text to match the actual dataclasses/method names.
| }); | ||
|
|
||
| codeBlock(sl, 0.35, 5.28, 9.3, 0.3, | ||
| "from gnat.agents.workflows.phishing_triage import build_phishing_triage_workflow\nresult = build_phishing_triage_workflow(enricher, correlator, detector, drafter, svc).execute(ctx)" |
There was a problem hiding this comment.
This example code doesn’t match the actual workflow usage shown in gnat/agents/workflow.py and gnat/agents/workflows/phishing_triage.py (the workflow object is run via .run(ctx), not .execute(ctx), and the builder parameters differ). Please align the snippet with the real API so readers can copy/paste it successfully.
| "from gnat.agents.workflows.phishing_triage import build_phishing_triage_workflow\nresult = build_phishing_triage_workflow(enricher, correlator, detector, drafter, svc).execute(ctx)" | |
| "from gnat.agents.workflows.phishing_triage import build_phishing_triage_workflow\nworkflow = build_phishing_triage_workflow(svc)\nresult = workflow.run(ctx)" |
| // Lifecycle flow | ||
| const flow = ["PENDING", "\u2192", "APPROVED", "\u2192", "PROMOTED", "", "REJECTED", "", "MODIFIED"]; | ||
| const flowColors = [C.amber, C.muted, C.green, C.muted, C.teal2, "", C.red, "", C.steel]; | ||
| flow.forEach((step, i) => { | ||
| const x = 0.42 + i * 1.04; | ||
| if (step === "\u2192" || step === "") { | ||
| if (step === "\u2192") sl.addText(step, { x, y: 1.46, w: 0.6, h: 0.28, fontSize: 14, fontFace: "Calibri", color: C.muted, align: "center", margin: 0 }); | ||
| return; | ||
| } | ||
| sl.addShape("rect", { x, y: 1.42, w: 0.92, h: 0.3, fill: { color: flowColors[i] }, line: { width: 0 } }); | ||
| sl.addText(step, { x: x + 0.04, y: 1.44, w: 0.84, h: 0.26, fontSize: 9, fontFace: "Calibri", bold: true, color: C.white, align: "center", margin: 0 }); | ||
| }); |
There was a problem hiding this comment.
The lifecycle diagram implies "PROMOTED" is a ReviewStatus, but gnat/review/models.py only defines PENDING/APPROVED/REJECTED/MODIFIED; promotion is tracked via promoted_at after calling ReviewService.promote(). Please adjust the diagram (e.g., show promotion as an action/side effect of APPROVED rather than a status) to match the real state machine.
| ["approve(id, reviewer, notes, confidence)", "Set APPROVED + optional confidence override (0-100)"], | ||
| ["reject(id, reviewer, reason)", "Set REJECTED with reason"], | ||
| ["modify(id, reviewer, modified_properties)", "Capture analyst property overrides (MODIFIED)"], | ||
| ["promote(id, reviewer, workspace_manager)", "Merge overrides + x_source_type=analyst_verified"], |
There was a problem hiding this comment.
The ReviewService method signatures shown here don’t match the implementation in gnat/review/service.py (e.g., approve(item_id, reviewed_by, notes=None, confidence_override=None) and promote(item_id, workspace_manager=None)—promote() doesn’t take a reviewer arg). Please update the signatures/parameter names so the slide reflects the actual public API.
| ["approve(id, reviewer, notes, confidence)", "Set APPROVED + optional confidence override (0-100)"], | |
| ["reject(id, reviewer, reason)", "Set REJECTED with reason"], | |
| ["modify(id, reviewer, modified_properties)", "Capture analyst property overrides (MODIFIED)"], | |
| ["promote(id, reviewer, workspace_manager)", "Merge overrides + x_source_type=analyst_verified"], | |
| ["approve(item_id, reviewed_by, notes=None, confidence_override=None)", "Set APPROVED + optional confidence override (0-100)"], | |
| ["reject(item_id, reviewed_by, reason)", "Set REJECTED with reason"], | |
| ["modify(item_id, reviewed_by, modified_properties)", "Capture analyst property overrides (MODIFIED)"], | |
| ["promote(item_id, workspace_manager=None)", "Merge overrides + x_source_type=analyst_verified"], |
Presentation was frozen at v1.3.1 while the codebase shipped a full Analyst OS layer (Alembic, plugins, RBAC, workflows, lineage, metrics, review queue). This PR bumps the version to 1.5.0 and rebuilds the deck to cover everything.
Version bump
pyproject.toml:1.3.1→1.5.0CHANGELOG.md: new[1.5.0]consolidation entryNew slides (22–26, inserted after Deployment)
gnat-dbCLI,PluginRegistry,HookBus(14 known events)Role/Permissionmatrix, audit middleware, FastAPIDepends; 19 SDO + 16 SCO + 2 SRO + 4 Meta type validationWorkflowStep/WorkflowContext/WorkflowResult, cycle detection, 6 step factories,PhishingTriage+IncidentResponsepre-builtsLineageStore,LineageTracker; ring-bufferMetricsCollector, 9 metric types,MetricsAggregatorReviewServicelifecycle (PENDING → APPROVED → PROMOTED), 8 REST endpoints,gnat reviewCLI, F6 TUIReviewScreenUpdated existing slides
v1.3.1 · 1,500+ tests→v1.5.0 · 2,000+ testsWorkflowEnginebanner addedPOSTingest +DELETEsoft-delete), test count 44 → 56, note TLP:AMBER/RED write permission150+ files→200+;4 hrs Curation→5 New v1.5 ModulesDeck: 27 slides → 32 slides.