Skip to content

docs(security): argue secure design principles in the assurance case - #767

Merged
CybotTM merged 1 commit into
mainfrom
docs/assurance-case-design-principles
Sep 22, 2026
Merged

CybotTM merged 1 commit into
mainfrom
docs/assurance-case-design-principles

Conversation

@CybotTM

@CybotTM CybotTM commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

Merging this lets the OpenSSF silver criterion assurance_case be answered Met, and hands the answer to the badge form so nobody has to retype it. Silver currently stands at 98 % with this as the one blocking criterion.

Why the criterion could not be claimed before

The criterion requires four things: a description of the threat model, clear identification of trust boundaries, an argument that secure design principles have been applied, and an argument that common implementation security weaknesses have been countered.

threat-model.md covers three of them — it has a Trust boundaries section, and its thirteen threats name LDAP injection, SQL injection, CSRF, XSS, privilege escalation in both directions and hostile integration data, each with the control that answers it. The third element had no home in either document: grep -i 'design principle|least privilege|defense in depth' across both returned nothing.

What the new section argues

Four principles, each from the configuration or code that implements it rather than as a claim about intent:

  • Deny by default — security.yaml ends on the catch-all ^/ rule, and the public entries above it are anchored (^/\.well-known/, ^/llms\.txt$) so a look-alike path cannot inherit access. For API tokens, RequireScopeSubscriber refuses a request to any controller that has not declared a scope.
  • Least privilege — ApiTokenAuthenticator builds the token's identity from the owning user's roles and the token's scopes, so a scope can only narrow. release.yml declares permissions: {} and grants per job; inside the reusable, the job that builds and signs holds contents: read and only the job that creates the release holds contents: write.
  • Complete mediation of half-finished logins — ^/2fa requires IS_AUTHENTICATED_2FA_IN_PROGRESS, passkey registration requires IS_AUTHENTICATED_FULLY, so a session resumed from the remember-me cookie cannot mint a permanent credential.
  • Defence in depth where one control is known to be insufficient — R4 assumes the database leaks, R7 assumes a token is stolen.

It closes by naming what the arguments do not cover: they are reconstructed from the code, and no formal design review precedes a change.

The proposal file

.bestpractices.json at the repository root is read by the BadgeApp, which offers its values in the form (spec). It carries only assurance_case, because that is the only criterion this commit makes true; everything else stays as recorded. Writing to the badge still needs a logged-in maintainer — the API accepts no token for writes — so a maintainer opens project 11719 and saves. The file removes the typing, not the login.

One claim corrected during writing

A first draft said RequireScopeCoverageTest fails when a controller is added without a scope. It does not: it reads every declared scope by reflection, fails on one outside the ApiScope taxonomy, and keeps a floor count against wholesale removal. The section says that instead.

Assisted by claude-code:claude-opus-5-5 — Session

The OpenSSF Best Practices silver criterion assurance_case requires four
things: a threat model, identified trust boundaries, an argument that
secure design principles have been applied, and an argument that common
implementation weaknesses have been countered. threat-model.md covered the
first, second and fourth. The third was missing, so the criterion could not
honestly be claimed.

The new section argues four principles from the configuration and code that
implement them: deny by default (the catch-all access rule and the anchored
public paths, the scope opt-in for API tokens), least privilege (a token
cannot exceed its issuing user; the release jobs hold contents:read except
the one that creates the release), complete mediation of half-finished
logins (2FA in progress, passkey registration requiring a full login), and
defence in depth where one control is known to be insufficient. It closes
with what the arguments do not cover.

.bestpractices.json proposes the resulting answer to the BadgeApp, which
reads that file and offers the value in the form. A maintainer still has to
open project 11719 and save; the file removes the typing, not the login.

Claude-Session: https://claude.ai/code/session_01GTLkVWstQvWJo4wT8pQFxs
Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI lite review requested due to automatic review settings September 22, 2026 17:26
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CybotTM

CybotTM commented Sep 22, 2026

Copy link
Copy Markdown
Member Author

Self-review: bd42dec

The bot review this pull request demands is unsatisfiable (Copilot quota wall or repeated bot failures on this head). The diff on this head was reviewed by the PR author; this comment is the on-the-record attestation the merge gate reads back. It stops matching on the next push.

@CybotTM
CybotTM merged commit 7a65353 into main Sep 22, 2026
25 of 26 checks passed
@CybotTM
CybotTM deleted the docs/assurance-case-design-principles branch September 22, 2026 20:26
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.

2 participants