Skip to content

docs(security): add "Release path & compromise scope" appendix (supersedes #232) - #240

Merged
Chris-Wolfgang merged 2 commits into
vNextfrom
docs/security-release-path-appendix
Jul 13, 2026
Merged

docs(security): add "Release path & compromise scope" appendix (supersedes #232)#240
Chris-Wolfgang merged 2 commits into
vNextfrom
docs/security-release-path-appendix

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Supersedes #232. Refs #151.

Rescopes the deliverable from the DR-runbook PR (#232) down to what's actually load-bearing for this repo: the ~10 DbClient-specific facts a maintainer would need at 2am if the release identity is compromised.

Dropped from the previous PR (moved to the fleet canonical at Chris-Wolfgang/repo-template#430 — will be canonicalized once, synced to every downstream):

  • Rotate credentials / revoke OAuth apps / sign out sessions
  • Unlist-vs-delete rationale
  • Advisory workflow walkthrough
  • Consumer notification template

Those are generic and duplicated 25× across the fleet would drift within a year. GitHub and NuGet's own docs update faster than a checked-in runbook.

Kept (this PR):

  • Release path is OIDC / NuGet Trusted Publishing (no long-lived key to rotate; any legacy key is an anomaly)
  • No fallback — compromise = GitHub-account-level incident
  • Owner + downstream-consumer status
  • Package coordinates for unlisting

Docs-only.

Post-merge: close #232 without merging.

Rescopes the deliverable from #232 down to the load-bearing bits:
the DbClient-specific facts a maintainer would need at 2am if the
release identity is compromised. The generic runbook material
(rotate credentials, revoke OAuth apps, unlist packages, publish
advisories, consumer-notification template) is dropped from this
repo — GitHub's and NuGet's own docs update faster than a
checked-in runbook, and duplicating that content across 25+
downstream repos would drift immediately.

Appendix covers:
- Release path: OIDC / NuGet Trusted Publishing (no long-lived
  API key exists; any legacy key is an immediate delete target).
- No fallback (compromise = GitHub-account-level incident).
- Owner + downstream-consumer status.
- Package coordinates for unlisting.

Fleet-canonical full runbook is tracked separately at
Chris-Wolfgang/repo-template#430 (per #151 AC).

Supersedes #232.
Refs #151.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

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.

Pull request overview

Adds a short, DbClient-specific appendix to SECURITY.md describing how releases are published (OIDC / NuGet Trusted Publishing) and what a maintainer should assume/verify if the release identity is compromised, while pointing generic incident-response guidance to the fleet-canonical tracking issue.

Changes:

  • Add “Release path & compromise scope” section to SECURITY.md.
  • Document the release workflow’s Trusted Publishing/OIDC posture, ownership, and NuGet package coordinates.
  • Link to the fleet-canonical runbook tracking issue to avoid duplicating generic IR steps.

Comment thread SECURITY.md Outdated
Comment thread SECURITY.md Outdated
Two findings, both accuracy-of-claim issues:

1. "No long-lived NUGET_API_KEY exists" was imprecise. The
   release workflow does bind an env var literally named
   NUGET_API_KEY — the value is minted per-run by
   NuGet/login@v1 via OIDC and passed to `dotnet nuget push`.
   That's ephemeral, not a persistent secret, but the earlier
   wording read as "the string 'NUGET_API_KEY' does not appear
   anywhere," which is wrong. Rewrote to describe what actually
   happens (ephemeral OIDC-minted push token, no long-lived
   secret dependency) and to acknowledge that keys can still
   exist on the NuGet account independently of CI — check-and-
   delete-anything-unrecognized becomes an incident action
   rather than a claim about repo state.

2. "Downstream consumers: none inside the Wolfgang.* org today"
   was a permanent-sounding statement that would rot the moment
   a new consumer landed. Qualified to "none known at time of
   writing" and added a re-check pointer (dotnet-outdated, GH
   code-search, NuGet Used By list) so the incident handler
   verifies rather than trusting a possibly-stale claim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Chris-Wolfgang

Copy link
Copy Markdown
Owner Author

Both findings addressed in f1ccd16:

  1. "No long-lived NUGET_API_KEY exists" was imprecise. The workflow does bind an env var literally named `NUGET_API_KEY` — but the value is minted per-run by `NuGet/login@v1` via OIDC. Rewrote to describe what actually happens (ephemeral OIDC-minted push token, no long-lived secret dependency) and shifted the "check for legacy keys on the NuGet account" from a claim about repo state to an incident action.
  2. "None inside the Wolfgang. org today" hard-coded a moment-in-time fact.* Qualified to "none known at time of writing" and added a re-check pointer (`dotnet-outdated`, GH code-search, NuGet Used By list) so incident handlers verify rather than trust the doc.

Both threads resolved.

@Chris-Wolfgang
Chris-Wolfgang merged commit 4fd9605 into vNext Jul 13, 2026
@Chris-Wolfgang
Chris-Wolfgang deleted the docs/security-release-path-appendix branch July 13, 2026 17:39
This was referenced Jul 15, 2026
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