Files
msd-core/SECURITY.md
Tom Boucher 79002a00cb chore(#518): rename npm package + bin to @opengsd/gsd-core (#519)
* chore: rename npm package + bin to @opengsd/gsd-core (functional)

- package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core,
  bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs
- package-lock.json: regenerated (npm install --package-lock-only)
- tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**,
  get-shit-done/bin/**, get-shit-done/workflows/**:
  applied the 4-rule replacement (scoped npm ref, GitHub repo path,
  bin/clone invocations) per #505 single-source refactor

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: sweep live references to @opengsd/gsd-core

Update all live documentation (README.md + translations, docs/**,
CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md,
docs/CANARY.md) to reflect the renamed package and repository.

Rules applied:
- @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name)
- open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo)
- GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org)
- bare bin/clone refs → gsd-core

CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**,
and .changeset/** are preserved byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: add negative lookbehind to slash-command regex in bug-2954 test

The extractSlashReferences regex matched /gsd-core inside npm package
URLs (@opengsd/gsd-core), producing a false /gsd:core command reference.
Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a
letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(#518): add changeset for package rename

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(#518): update package-identity expectations to the renamed coordinates

The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo
open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL
package.json, so their expected literals must follow the rename. The drift-lint
unit test is left as-is — its SEAM is a self-consistent fixture and its
stale-literal detection cases would shift if altered; the live-repo scan in it
already passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:25:02 -04:00

149 lines
5.2 KiB
Markdown

# Security Policy
## Reporting a Vulnerability
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them via a **private GitHub security advisory**:
**https://github.com/open-gsd/gsd-core/security/advisories/new**
Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Any suggested fixes (optional)
## Response Timeline
- **Acknowledgment**: Within 48 hours
- **Initial assessment**: Within 1 week
- **Fix timeline**: Depends on severity, but we aim for:
- Critical: 24-48 hours
- High: 1 week
- Medium/Low: Next release
## Scope
Security issues in the GSD codebase that could:
- Execute arbitrary code on user machines
- Expose sensitive data (API keys, credentials)
- Compromise the integrity of generated plans/code
## Recognition
We appreciate responsible disclosure and will credit reporters in release notes (unless you prefer to remain anonymous).
## Org-level security baseline
This file covers how to report individual vulnerabilities. For the broader
org-wide security posture — scanner controls, incident-audit checklists,
ownership model, and rollout plan — see:
[`docs/security/baseline.md`](docs/security/baseline.md)
## Secret-Scan Exclusion Governance
Secret-scanning exclusions (`.secretscanignore`) require structured annotations. Bare paths are accepted in default mode with a deprecation warning but are rejected in strict mode. The lint runs on every PR.
### Annotation format
```
# allow: <pattern> reason="..." owner="..." expires="YYYY-MM-DD" [rule-id="..."]
<pattern>
```
Required keys: `reason`, `owner`, `expires`. Wildcard patterns (`**`, `*.ext`) also require `rule-id`.
Lint locally: `scripts/secret-scan-lint.sh --file .secretscanignore`
### Periodic reduced-exclusion scan (release and security-review lanes)
Run this during every release and scheduled security review:
```bash
scripts/secret-scan.sh --diff origin/main --strict
```
The `--strict` flag:
- Does **not** honour grandfathered (un-annotated) exclusions — those files are scanned.
- Skips any exclusion whose `expires` date is in the past — those files are scanned.
- Is intended to surface accumulated exclusion debt that default mode masks.
If `--strict` finds findings that default mode does not, those findings represent either (a) an entry that should have been annotated and renewed, or (b) an actual secret that was only hidden by a stale exclusion. In both cases: investigate, remediate, and update the exclusion annotation.
References:
- GitGuardian exclusion annotation convention: https://docs.gitguardian.com/internal-repositories-monitoring/integrations/cli/secrets
- CNCF Security TAG threat-model exception lifecycle: https://github.com/cncf/tag-security/blob/main/community/working-groups/threat-modeling/templates/threats.md
---
## Dependency Integrity Verification
### Purpose
The `scripts/check-npm-integrity.cjs` gate detects three classes of dependency
drift that can silently introduce security or reliability risk:
- **Invalid** — an installed package version does not satisfy the declared semver
range (e.g., `ws@8.20.0` installed when `8.20.1` is declared). This was the
original incident that prompted this gate.
- **Missing** — a declared dependency is absent from `node_modules/`.
- **Extraneous** — a package is present in `node_modules/` but not declared as a
dependency.
This aligns with NIST SSDF PW.4.1 (use components from well-governed, secure
sources: https://csrc.nist.gov/publications/detail/sp/800-218/final) and the
OpenSSF Scorecard "Pinned-Dependencies" check
(https://github.com/ossf/scorecard/blob/main/docs/checks.md#pinned-dependencies).
### Invoking locally
```bash
node scripts/check-npm-integrity.cjs
# or via npm script:
npm run check:integrity
```
The script exits 0 on a clean install and 1 on any finding, with a structured
report to stderr listing every offender and both the declared and installed
versions for invalid packages.
Options:
- `--ignore-extraneous` — suppress extraneous-only failures (useful when
intentionally adding packages before updating the lockfile)
- `--help` — print usage and exit 0
### Remediation
The canonical fix for any drift is:
```bash
rm -rf node_modules && npm ci
```
Then verify with `npm run check:integrity` before committing.
### Bypass policy
There is no bypass flag. If the gate must be skipped for a specific commit
(e.g., during a lockfile migration), document the reason in the commit message.
CI workflow steps can be skipped via `if: false` with a comment explaining why
and a follow-up issue number. Any such skip must be reversed in a subsequent
commit before the PR is merged.
### Scope
The gate runs `npm ls --all --json` at the repository root. The `sdk/`
sub-directory is a separate, non-workspace package and is out of scope for this
single invocation. If `sdk/` is ever declared as a workspace in root
`package.json`, it will be covered automatically (npm >=7 traverses workspaces
by default).
### CI coverage
The gate runs in:
- `test.yml` — all matrix jobs and the coverage job, after `npm ci`
- `release.yml` — rc and finalize jobs, after `npm ci`
- `security-scan.yml` — before all diff-based source scans