Skip to content

fix(core): enforce severity contract v1 - #308

Merged
ritiksah141 merged 3 commits into
devfrom
fix/295-severity-contract-v1
Aug 28, 2026
Merged

fix(core): enforce severity contract v1#308
ritiksah141 merged 3 commits into
devfrom
fix/295-severity-contract-v1

Conversation

@m-khan-97

Copy link
Copy Markdown
Collaborator

Why

We have two CRITICAL scanner rules today, but the old scoring paths treated CRITICAL as a zero-point deduction. That meant an all-critical scan could still report a score of 100, while resources and prioritization could downgrade the same findings to NONE or LOW.

For an enterprise security product, that is a trust failure. I have treated this as a cross-product data contract rather than patching individual screens.

What I changed

  • Added a versioned severity contract covering IDs, aliases, rank, posture weight, matrix risk, labels, colours, and UI tones.
  • Wired the scanner, persistence layer, API validation, AI ordering, resources, prioritization, compliance output, Sentinel ingestion, and frontend to that contract.
  • Made unknown severities fail closed. INFORMATIONAL is accepted only as an input alias and is stored and returned as INFO.
  • Added a migration that inventories existing values, normalizes supported legacy data, rejects unknown data, enforces the database constraint, repairs completed scan scores, and records score-contract provenance.
  • Changed deployment order so the migration-owning API must become live before a worker for the same SHA is created.
  • Added contract, scanner, persistence, API, monitoring, UI-wiring, and rollout-order regressions, plus contributor and architecture documentation.

Verification

  • 128 focused backend and contract tests passed.
  • Broader local suite: 721 passed, 3 skipped. Three dependency-only modules unavailable on this host were excluded; clean CI will install and exercise the complete dependency set.
  • Ruff check and format, Python compilation, and diff checks passed.
  • Node 22.22: severity contract tests 5/5, ESLint passed, and the production Vite build completed successfully.
  • The frontend mirror is byte-identical to the canonical contract.

Rollout note

This migration intentionally corrects historical completed scores, so score changes are expected and auditable. Contract provenance stays nullable during rollout: if a legacy worker finishes after the schema change, its old score cannot be mislabeled as v1. The API now has to finish deployment before the new worker is created.

Before production, I want this migration run against a production-sized staging copy and the old workers drained. Downgrading the schema will not pretend the previously incorrect scores were valid.

Kept out of this PR

Closes #295
Related to #263 and #303

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

ritiksah141
ritiksah141 previously approved these changes Aug 21, 2026

@ritiksah141 ritiksah141 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good.

@TFT444 TFT444 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration d8e4f6a1b2c3 has the same down_revision = 'c7a2e9f1b3d4' as PR #310's migration. These two PRs cannot both merge without Alembic branching. Coordinate with the #310 author so one migration correctly chains off the other before either is merged.

@m-khan-97

Copy link
Copy Markdown
Collaborator Author

@TFT444 @parthrohit22, thanks for catching the Alembic collision. I have rebased #308 onto the latest dev and kept d8e4f6a1b2c3 directly after the current dev head c7a2e9f1b3d4. The intended order is #308 first because #293 already depends on the severity contract; after #308 merges, #310 should rebase onto dev and chain its migration from d8e4f6a1b2c3 rather than creating a sibling head.\n\nI also tightened scan persistence during the rebase: retries now replace findings atomically, child findings are forced onto the parent scan ID, and SQL failures roll back before the worker records failure. Local verification: 42 focused tests passed; broader backend run passed 747 tests with 5 expected skips. Fresh CI is running on a194a71. Please re-review once it is green.

@m-khan-97
m-khan-97 requested a review from TFT444 August 23, 2026 22:52
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 24, 2026
…tion after openshield-org#308

get_score() had the same bug get_compliance_score() was fixed for: folding
the completed-scan lookup into a `scan_id = (SELECT ...)` subquery cannot
distinguish "no completed scan exists" from "the latest completed scan
found nothing" - both produce zero rows, so the former was silently
reported as a perfect 100 with no actual evidence behind it. get_score()
now checks for a completed scan first and returns an explicit
NO_SCAN_DATA result (score: null) when none exists, only computing a
real score once one has run.

Also: alembic/versions/3a76ff935bf6 shared down_revision=c7a2e9f1b3d4
with PR openshield-org#308's migration, which forks the Alembic revision graph if both
merge independently. Chained this one after openshield-org#308's d8e4f6a1b2c3 instead
(openshield-org#308 was opened first); noted in the migration's docstring that the
ordering needs to flip if openshield-org#308 ends up merging after this PR.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 24, 2026
… merge-time coordination

Chaining 3a76ff935bf6's down_revision onto PR openshield-org#308's d8e4f6a1b2c3 broke
this PR's own CI: alembic upgrade head resolves the revision map from
whatever files exist in the branch it's run against, and openshield-org#308's
migration file doesn't exist here since openshield-org#308 hasn't merged yet
(KeyError: 'd8e4f6a1b2c3' during Apply database migrations).

Reverted to down_revision=c7a2e9f1b3d4 so this branch's own migration
chain resolves again. The actual fork between this migration and openshield-org#308's
can only be resolved once one of the two merges - documented in the
migration's docstring for whoever merges second.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>

@parthrohit22 parthrohit22 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration is genuinely well-built: validate (fail loud via RAISE EXCEPTION on any out-of-set severity) -> normalize -> add column -> add CHECK NOT VALID then VALIDATE CONSTRAINT separately (correct low-lock ordering) -> repair scores only once the constraint guarantees every severity is canonical. Hand-verified the score arithmetic (GREATEST(0, 100 - COALESCE(SUM(deduction),0)) with CRITICAL=20/HIGH=10/MEDIUM=5/LOW=2/INFO=0) against a few example rows and it matches openshield/severity.py exactly, and the contract/JSON/frontend-mirror sync is byte-exact and CI-enforced (sync-severity-contract.mjs --check). scanner/engine.py re-raising SeverityContractError out of the per-rule try/except (rather than silently dropping just that finding) and worker.py marking the scan failed rather than completed is exactly the fail-loud behavior this PR is going for, and it's correct.

One real gap though, left as an inline comment: sentinel/ingest.py still silently defaults a missing severity key to MEDIUM in a function this PR otherwise rewrote to fail loud on bad severities. That's the exact anti-pattern the PR description cites as the whole reason for this change, in a file the PR already touched, so I don't think it should ship as a known gap.

Three more non-blocking notes, no action needed to merge:

  • test_v1_migration_freezes_the_same_ids_and_weights_as_the_contract only does static text-matching against the migration source (asserts a string like "WHEN 'CRITICAL' THEN 20" appears); the actual data-repair SQL only ever runs against an empty DB in CI. Worth a real integration test that seeds a couple of completed scans with mixed severities and asserts the resulting scans.score, since that's the riskiest, most novel part of this migration.
  • That same test couples a frozen historical migration file to the live severity.py contract module - if a future v2 contract changes a weight, this test would fail unless someone edits an already-applied migration, which docs/severity-contract.md's own guidance says not to do. Worth flagging for whoever writes v2.
  • This PR is what introduces synchronous throwing on unrecognized severity into more frontend components (SeverityBadge/RiskBadge/severityDefinition), and there's no ErrorBoundary anywhere in the frontend - an unexpected value reaching one of these would blank the whole page rather than degrade. Not a regression from correct behavior, just worth a follow-up ticket.

Separately: gh pr view shows this PR conflicting against dev right now (unrelated to the code review) - flagging since #310 also touches scans via a migration and the two would fork the Alembic revision graph if merged independently; I've noted the coordination needed on that side.

Full suite (Python 3.11, this sandbox's .venv targets 3.14 which can't build psycopg2-binary): 732 passed, 3 skipped, 2 failed - the 2 failures are test_observability.py hitting an unreachable postgres host in this environment, unrelated to this diff. All severity-contract-relevant tests (severity_contract, sentinel_input_validation, prioritization, resources, clean_scan, engine_integration, input_validation, error_exposure, render_deploy_config) pass 99/99, and frontend npm run test:severity passes 5/5 including the contract sync check.

Comment thread sentinel/ingest.py Outdated
sev = _safe_text(raw.get("severity", "MEDIUM"), "severity", maximum=16).upper()
if sev not in sev_map:
raise ValidationError("severity must be CRITICAL, HIGH, MEDIUM, LOW, or INFO")
raw_severity = _safe_text(raw.get("severity", "MEDIUM"), "severity", maximum=16)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still defaults a missing severity key to "MEDIUM" before validation runs. The surrounding logic in this same function was rewritten by this PR to raise on an unrecognized severity value, but a missing key silently becomes MEDIUM rather than failing loud - which is exactly the "an all-critical scan could still report a passing score" trust problem this PR's own description calls out as the reason for the whole change.

Failure scenario: a hand-edited or corrupted findings payload fed to sentinel/ingest.py is missing severity on a record that was actually CRITICAL. Instead of the ingest rejecting the record, it ships a fabricated MEDIUM to the customer's Sentinel workspace. tests/test_sentinel_input_validation.py only exercises explicit invalid/valid severity strings, never a missing key, so this is currently unguarded.

api/validation.py's findings_list handles the same situation by leaving severity as None rather than coercing it - suggest matching that here (raise/reject on missing, don't default).

Signed-off-by: m-khan-97 <ibrahim.logix@gmail.com>
Signed-off-by: m-khan-97 <ibrahim.logix@gmail.com>
Signed-off-by: m-khan-97 <ibrahim.logix@gmail.com>
@m-khan-97
m-khan-97 force-pushed the fix/295-severity-contract-v1 branch from a194a71 to 5937dab Compare August 24, 2026 16:11
@m-khan-97

Copy link
Copy Markdown
Collaborator Author

@parthrohit22, thanks for catching the Sentinel gap. It is fixed in 5937dab: missing, null, and empty severities are now rejected instead of defaulting to MEDIUM, with regression coverage for all three cases. I also rebased onto the latest dev and preserved both #287's dashboard load/error states and the severity-contract behavior during conflict resolution.\n\nVerification: 102 severity-focused tests passed; the broader backend suite passed 750 tests with 5 expected skips. Fresh CI is running. Please re-review once it is green.

@parthrohit22 parthrohit22 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gap I flagged is genuinely closed. Pulled this branch's actual head into a clean clone and verified rather than trusting the summary: sentinel/ingest.py now raises ValidationError("severity is required for every Sentinel finding") when the key is missing, None, or empty string, before it ever reaches _safe_text/normalize_severity - the exact "an all-critical scan could still report a passing score" anti-pattern this PR set out to eliminate no longer has a gap in the one file it left open last round. test_normalise_rejects_missing_or_empty_severity is parametrized on all three real cases ({}, {"severity": None}, {"severity": ""}) and I ran it myself: passes, along with the rest of test_sentinel_input_validation.py and all 22 tests in test_severity_contract.py. Full suite: 735 passed, 5 skipped, 0 failed. Ruff clean. Migration chain resolves cleanly (alembic heads -> single head at d8e4f6a1b2c3).

None of my three non-blocking notes from last round needed to hold this up and I'm not asking for them now - just flagging I didn't see them addressed in case they got lost: the migration-integration-test gap (data-repair SQL still only runs against an empty DB in CI), the frozen-migration/live-contract coupling in test_v1_migration_freezes_the_same_ids_and_weights_as_the_contract, and the missing frontend ErrorBoundary now that more components throw synchronously on bad severity.

Migration coordination with #310 is already tracked on both sides (you kept d8e4f6a1b2c3 chained after c7a2e9f1b3d4 here, and I've got #310 documented to rebase onto whichever of us merges second) - not a new blocker, just confirming it's still the right call now that I can see both PRs' current state.

Approving.

@ritiksah141
ritiksah141 requested review from parthrohit22 and ritiksah141 and removed request for vogonPrayas August 27, 2026 23:48
@ritiksah141
ritiksah141 removed the request for review from SHAURYAKSHARMA24 August 27, 2026 23:48
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
…tion after openshield-org#308

get_score() had the same bug get_compliance_score() was fixed for: folding
the completed-scan lookup into a `scan_id = (SELECT ...)` subquery cannot
distinguish "no completed scan exists" from "the latest completed scan
found nothing" - both produce zero rows, so the former was silently
reported as a perfect 100 with no actual evidence behind it. get_score()
now checks for a completed scan first and returns an explicit
NO_SCAN_DATA result (score: null) when none exists, only computing a
real score once one has run.

Also: alembic/versions/3a76ff935bf6 shared down_revision=c7a2e9f1b3d4
with PR openshield-org#308's migration, which forks the Alembic revision graph if both
merge independently. Chained this one after openshield-org#308's d8e4f6a1b2c3 instead
(openshield-org#308 was opened first); noted in the migration's docstring that the
ordering needs to flip if openshield-org#308 ends up merging after this PR.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
… merge-time coordination

Chaining 3a76ff935bf6's down_revision onto PR openshield-org#308's d8e4f6a1b2c3 broke
this PR's own CI: alembic upgrade head resolves the revision map from
whatever files exist in the branch it's run against, and openshield-org#308's
migration file doesn't exist here since openshield-org#308 hasn't merged yet
(KeyError: 'd8e4f6a1b2c3' during Apply database migrations).

Reverted to down_revision=c7a2e9f1b3d4 so this branch's own migration
chain resolves again. The actual fork between this migration and openshield-org#308's
can only be resolved once one of the two merges - documented in the
migration's docstring for whoever merges second.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
…tion after openshield-org#308

get_score() had the same bug get_compliance_score() was fixed for: folding
the completed-scan lookup into a `scan_id = (SELECT ...)` subquery cannot
distinguish "no completed scan exists" from "the latest completed scan
found nothing" - both produce zero rows, so the former was silently
reported as a perfect 100 with no actual evidence behind it. get_score()
now checks for a completed scan first and returns an explicit
NO_SCAN_DATA result (score: null) when none exists, only computing a
real score once one has run.

Also: alembic/versions/3a76ff935bf6 shared down_revision=c7a2e9f1b3d4
with PR openshield-org#308's migration, which forks the Alembic revision graph if both
merge independently. Chained this one after openshield-org#308's d8e4f6a1b2c3 instead
(openshield-org#308 was opened first); noted in the migration's docstring that the
ordering needs to flip if openshield-org#308 ends up merging after this PR.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
… merge-time coordination

Chaining 3a76ff935bf6's down_revision onto PR openshield-org#308's d8e4f6a1b2c3 broke
this PR's own CI: alembic upgrade head resolves the revision map from
whatever files exist in the branch it's run against, and openshield-org#308's
migration file doesn't exist here since openshield-org#308 hasn't merged yet
(KeyError: 'd8e4f6a1b2c3' during Apply database migrations).

Reverted to down_revision=c7a2e9f1b3d4 so this branch's own migration
chain resolves again. The actual fork between this migration and openshield-org#308's
can only be resolved once one of the two merges - documented in the
migration's docstring for whoever merges second.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>

@parthrohit22 parthrohit22 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed from scratch on the current head - the code hasn't changed since my last approval (5937dab is both the commit I approved and today's head), but you re-requested review and I'm not going to just rubber-stamp my own old finding without checking, so I re-verified everything myself rather than trusting memory.

What I re-ran and re-checked just now:

  • All 70 of this PR's own new/changed tests (test_severity_contract.py, test_sentinel_input_validation.py, test_engine_integration.py, test_clean_scan.py, test_prioritization.py, test_resources.py, test_input_validation.py) - all pass.
  • Full backend suite: 726 passed. (One unrelated failure locally - test_chroma_default_embedding_uses_onnx_runtime - is this branch's own stale copy of tests/test_rag_dependencies.py from before #317 removed chromadb; not a defect in this PR's own diff, just a symptom of the branch being unrebased since before #316/#309/#317 landed on dev. See the rebase note below.)
  • frontend/src/utils/severity.test.mjs: 5/5 pass.
  • Read the actual sentinel/ingest.py fix directly (not just the test result) to confirm my original finding is really closed: missing/empty severity is rejected before normalization is even attempted (line 75-76), and anything outside the contract is rejected via normalize_severity() + SeverityContractError (line 78-81). Matches the test coverage exactly - confirmed, not just claimed.
  • Read the full migration (d8e4f6a1b2c3_severity_contract_v1.py) line by line. This is genuinely careful work: a pre-flight DO $$ ... RAISE EXCEPTION block that refuses to proceed if any existing severity value can't be mapped (fails loud instead of silently corrupting data), the ADD CONSTRAINT ... NOT VALID + VALIDATE CONSTRAINT pattern (avoids a long-lived table lock on a large findings table - the right way to add a CHECK constraint in production Postgres, not the naive one-shot ALTER TABLE ADD CONSTRAINT), and a rescore of historical completed scans using the exact same weights as contracts/severity.v1.json (verified: 20/10/5/2/0 match exactly). The downgrade explicitly documents that corrected historical scores are not reverted, rather than leaving that ambiguous.

The one thing still open, and it's not something this PR can fix alone:

TFT444's CHANGES_REQUESTED is still active and still correct: d8e4f6a1b2c3 and PR #310's migration both chain off c7a2e9f1b3d4, and merging both as-is forks the Alembic revision graph. I can't approve that away, and neither PR can unilaterally resolve it - I tried pointing my own PR's migration at an unmerged sibling's revision file and it breaks that PR's own CI (KeyError on a revision that doesn't exist outside the sibling's branch), so the fix genuinely requires a merge-order decision: whichever of #308/#310 lands second rebases onto the new dev head and repoints down_revision. That's a maintainer call on ordering, not a code change here. I've already added a CI check on my side (#310) that asserts alembic heads returns exactly one head, so if this does get missed at merge time, it fails loudly instead of silently forking.

Also worth flagging since I checked it directly: this branch's merge-base with dev predates #316, #309, and #317 - it's meaningfully behind. Doesn't block my approval (the code itself is correct and tested), but it should be rebased before/at merge so CI reflects current dev rather than a stale pip-audit/test snapshot.

Approving - the actual code is solid and my original findings are genuinely fixed. The Alembic coordination is real but is a merge-order decision for a maintainer, not a defect in this PR.

Comment thread sentinel/ingest.py
if sev not in sev_map:
raise ValidationError("severity must be CRITICAL, HIGH, MEDIUM, LOW, or INFO")
if raw.get("severity") in (None, ""):
raise ValidationError("severity is required for every Sentinel finding")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed this is the actual fix for my original finding, not just claimed - read it directly: missing/null/empty severity is rejected right here, before normalize_severity() is even called, so it can't fall through to a silent default. Matches test_normalise_rejects_missing_or_empty_severity's three parametrized cases, which I ran myself.


# Revision identifiers, used by Alembic.
revision: str = "d8e4f6a1b2c3"
down_revision: Union[str, Sequence[str], None] = "c7a2e9f1b3d4"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the fork with PR #310's migration lives - both chain off c7a2e9f1b3d4. Not something fixable from this side alone (confirmed by trying the equivalent on my own PR's migration - pointing down_revision at an unmerged sibling's revision file breaks that PR's own CI outright). This needs a merge-order call: whichever of #308/#310 merges second rebases onto the new head and repoints this. Not blocking my approval - flagging for whoever merges.

@Vishnu2707
Vishnu2707 removed the request for review from TFT444 August 28, 2026 13:05

@Vishnu2707 Vishnu2707 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. LGTM!

@Vishnu2707

Copy link
Copy Markdown
Member

@TFT444 - Please approve and merge if everything looks good from your side.

@ritiksah141
ritiksah141 merged commit c54d591 into dev Aug 28, 2026
20 checks passed
@ritiksah141
ritiksah141 deleted the fix/295-severity-contract-v1 branch August 28, 2026 16:18
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
…tion after openshield-org#308

get_score() had the same bug get_compliance_score() was fixed for: folding
the completed-scan lookup into a `scan_id = (SELECT ...)` subquery cannot
distinguish "no completed scan exists" from "the latest completed scan
found nothing" - both produce zero rows, so the former was silently
reported as a perfect 100 with no actual evidence behind it. get_score()
now checks for a completed scan first and returns an explicit
NO_SCAN_DATA result (score: null) when none exists, only computing a
real score once one has run.

Also: alembic/versions/3a76ff935bf6 shared down_revision=c7a2e9f1b3d4
with PR openshield-org#308's migration, which forks the Alembic revision graph if both
merge independently. Chained this one after openshield-org#308's d8e4f6a1b2c3 instead
(openshield-org#308 was opened first); noted in the migration's docstring that the
ordering needs to flip if openshield-org#308 ends up merging after this PR.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
… merge-time coordination

Chaining 3a76ff935bf6's down_revision onto PR openshield-org#308's d8e4f6a1b2c3 broke
this PR's own CI: alembic upgrade head resolves the revision map from
whatever files exist in the branch it's run against, and openshield-org#308's
migration file doesn't exist here since openshield-org#308 hasn't merged yet
(KeyError: 'd8e4f6a1b2c3' during Apply database migrations).

Reverted to down_revision=c7a2e9f1b3d4 so this branch's own migration
chain resolves again. The actual fork between this migration and openshield-org#308's
can only be resolved once one of the two merges - documented in the
migration's docstring for whoever merges second.

Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
parthrohit22 added a commit to parthrohit22/openshield that referenced this pull request Aug 28, 2026
…ontract v1

Rebases this branch onto dev now that PR openshield-org#308 (severity contract v1,
d8e4f6a1b2c3) has merged, and repoints 3a76ff935bf6's down_revision at
it as planned in the migration's own docstring, so `alembic heads`
resolves to a single head again.

Reconciles openshield-org#308's atomic/idempotent save_scan() and score_counts()
usage with this branch's compliance-mapping-snapshot and evidence-
schema work in api/models/finding.py, api-reference.md, and
architecture.md, and merges the CI step lists in ci.yml so both
suites run.

Two issues surfaced while reconciling the two branches' code, fixed
here rather than deferred:

- get_compliance_score()'s severity/category grouping query was about
  to run against openshield-org#308's finding.py through the RealDictCursor this
  branch used elsewhere in the same method. RealDictRow has no
  __iter__ override, so positional unpacking of its rows silently
  reads back key names instead of values. Restored openshield-org#308's own plain
  cursor for that one query, matching its tested convention, instead
  of carrying the bug or rewriting openshield-org#308's already-merged code.
- .github/scripts/validate_mapping_pack.py flagged AZ-CMP-007 (added
  by the already-merged openshield-org#307) as missing the evidence-schema fields
  this branch's mapping-pack validation requires, across all four
  framework files. Filled them in following the existing sibling-rule
  conventions in each file.

Updates the affected tests in test_clean_scan.py,
test_compliance_scoring.py, and test_severity_contract.py for the new
call shapes, and fixes frontend/src/utils/api.test.mjs's module-
loading harness for api.js's new severity.js import from openshield-org#308
(stubbed, since the functions under test here don't call it and
severity.js has its own dedicated suite).

Verified: alembic heads (single head) and a full upgrade/downgrade/
upgrade/heads cycle against a local Postgres instance; full pytest
suite (818 passed, 3 skipped); ruff check and format --check; mapping-
pack validator; and the full frontend test/lint/build suite.

Signed-off-by: Parth J Rohit <parthrohit60@gmail.com>
Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: handle CRITICAL consistently across scoring, APIs, reports, and frontend

5 participants