feat: import standards and map controls to requirements - #5
Merged
Merged
Conversation
Standards arrive whole in one import and their requirements are read in the order the standard states them, filterable by whether any control is mapped and by the reference people cite. A control's requirements are replaced as a set, guarded by an ETag computed from the set's contents, and the mapping is readable from both ends. Collection queries and the import refuse unknown fields rather than silently answering a different question. Evidence, attestation and file storage follow separately. Signed-off-by: quality-runtime[bot] <330432719+quality-runtime[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the first half of
requirement → control → evidenceto the API: organizations can import a standard, read its requirements in the order the standard states them, and map controls to the requirements they are meant to address. Evidence, attestation and file storage follow in a separate PR.What changes
Import a standard whole.
POST /standardstakes the name, edition and 1–2,000 requirements in one transaction;positioncomes from array order. A repeated name and edition is409(targetedON CONFLICT). Imports get a 1 MiB body limit on that exact route; everything else keeps 64 KiB.Read requirements as the document states them.
GET /standards/{id}/requirementspages by(position, id)ascending — a second cursor ordering beside newest-first — and filters by?mapped=true|falseand?reference=(exact match after trimming, for clause IDs cited in commits).Requirements stand on their own.
GET /requirements/{id}andGET /requirements/{id}/controlsread the mapping from the requirement's end.Map controls as a set.
PUT /controls/{id}/requirementsreplaces the whole set and records one audit event on the control. Its ETag hashes the set's contents and is the same on every page ofGET /controls/{id}/requirements, so a client can write back only what it read:Unknown query parameters and import fields are refused, not dropped: a misspelt
?maped=falsewould otherwise return the unfiltered list.Decisions worth checking
positionallowed to tie.PUT,FOR UPDATEon the control plusFOR KEY SHAREon the named requirements, and why a retired control can still be remapped.mapped, notcovered.Reads that check a parent and then list its children, or return a page with the set's ETag, run in
repeatable readso both answers describe one moment.Verification
On the committed tree, checked out clean:
bun run check— format, lint, typesbun run test— 442 passing, including the real-PostgreSQL race suite (TEST_DATABASE_URLset): a conditional remapping against a competing lock, and a requirement's standard deleted mid-replacement answering400rather than a foreign-key500uvx --from 'reuse[charset-normalizer]' reuse lintKnown follow-ups