feat(m4): REST endpoints + admin sync + /diag/reset consistency
- GET /api/v1/mitre/tactics, /techniques?tactic=&q=, /subtechniques?technique=&q=
(paginated, ILIKE search on name + external_id, @require_auth only — MITRE
is public reference material).
- GET /api/v1/mitre/status: last_sync, version, source_url + the pinned
defaults (default_url, default_version) for the SPA badge.
- POST /api/v1/mitre/sync: @require_perm("mitre.sync"). Body supports
{source, expected_sha256, allow_unverified} — defaults inherit the pin.
- /diag/reset now also TRUNCATEs the mitre_* tables alongside settings so a
freshly-reset stack has GET /mitre/status and GET /mitre/tactics agree
("no data, no last_sync"). Previously the catalogue persisted while the
metadata was wiped, leaving status to lie. The e2e suite re-syncs in
beforeAll.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -66,12 +66,23 @@ def reset_test_state():
|
||||
|
||||
try:
|
||||
with get_engine().begin() as conn:
|
||||
# Auth + RBAC + settings reset.
|
||||
conn.execute(
|
||||
text(
|
||||
"TRUNCATE users, refresh_tokens, invitations, invitation_groups, "
|
||||
"user_groups, settings, groups RESTART IDENTITY CASCADE"
|
||||
)
|
||||
)
|
||||
# MITRE reference reset — kept in sync with `settings` so a freshly
|
||||
# reset stack has `GET /mitre/status` and `GET /mitre/tactics` agree
|
||||
# ("no data, no last_sync"). The e2e suite re-syncs via /mitre/sync
|
||||
# when it needs catalogue data.
|
||||
conn.execute(
|
||||
text(
|
||||
"TRUNCATE mitre_technique_tactics, mitre_subtechniques, "
|
||||
"mitre_techniques, mitre_tactics RESTART IDENTITY CASCADE"
|
||||
)
|
||||
)
|
||||
except SQLAlchemyError as e:
|
||||
log.error("metamorph.diag.reset_failed", extra={"error": str(e)})
|
||||
return jsonify({"reset": False, "error": "database_error"}), 500
|
||||
|
||||
Reference in New Issue
Block a user