Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
437fc9e
docs: add architecture audit report and scope the Critical hardening …
SHcommit Sep 1, 2026
fc46830
feat: add atomic write and directory lock primitives
SHcommit Sep 1, 2026
49ede49
fix: make ADR creation race-free under concurrent invocation
SHcommit Sep 1, 2026
68bbd98
fix: make exception creation race-free under concurrent invocation
SHcommit Sep 1, 2026
cec7215
fix: make SUPERSEDE writes atomic and lock-protected
SHcommit Sep 1, 2026
c0ff907
fix: add ReDoS timeout guard to CHECK's author-supplied regex patterns
SHcommit Sep 1, 2026
7afdcd5
fix: escape ADR titles in generated README to prevent link injection
SHcommit Sep 1, 2026
11c8f4b
feat: add structured stderr logging with correlation IDs
SHcommit Sep 1, 2026
f0cbc86
docs: close out Critical hardening backlog items
SHcommit Sep 1, 2026
f92c8f5
fix: reject a --dir/--root that escapes the repository root
SHcommit Sep 1, 2026
52bd761
ci: measure and gate branch coverage at 85%
SHcommit Sep 1, 2026
305c836
feat: add typed result contracts and a mypy --strict CI gate
SHcommit Sep 1, 2026
46dd863
feat: add --diagnostic flag for per-invocation timing
SHcommit Sep 1, 2026
9708bb2
test: prove atomic_write_text survives a mid-write SIGKILL
SHcommit Sep 1, 2026
cff3d5e
feat: extract a shared adapter-manifest validator
SHcommit Sep 1, 2026
9a974b7
docs: close out High-priority hardening backlog items
SHcommit Sep 1, 2026
41998a2
feat: add a common domain-error base class and fix unhandled path-esc…
SHcommit Sep 1, 2026
e3d592b
test: detect drift between JSON Schema docs and runtime validators
SHcommit Sep 1, 2026
2933575
feat: extend output contract coverage to CHECK's result shape
SHcommit Sep 1, 2026
d7368f6
test: add a bulk-ADR performance sanity check
SHcommit Sep 1, 2026
c3ed01d
feat: add a TTY-only human summary line on stderr
SHcommit Sep 1, 2026
77ce206
docs: close out Medium-priority hardening backlog items
SHcommit Sep 1, 2026
1df6066
feat: extend output contract coverage to all 16 commands
SHcommit Sep 1, 2026
5859f99
docs: close out output contract coverage item
SHcommit Sep 1, 2026
8f7cd46
docs: populate cross-session handoff summary before switching sessions
SHcommit Sep 1, 2026
0a0db8a
Merge remote-tracking branch 'origin/develop' into feature/analyzing-…
SHcommit Sep 1, 2026
a7f2d3b
docs: add Low-priority tier to improvements.md from enterprise-adopti…
SHcommit Sep 1, 2026
c46b2e6
docs: add audit-report Low-risk items to improvements.md (corrects ea…
SHcommit Sep 1, 2026
0307a1c
feat: allow proposed->deprecated transition; document constraints: bl…
SHcommit Sep 1, 2026
9a44342
feat: lint constraints: blocks at CREATE/STATUS time, not just CHECK …
SHcommit Sep 1, 2026
466ffed
docs: close out 3 of 4 audit-report Low items, note parallel Codex work
SHcommit Sep 1, 2026
9a0de45
docs: design adoption metrics collector
SHcommit Sep 1, 2026
70e2dd2
feat: calculate adoption metrics from normalized events
SHcommit Sep 1, 2026
8ee84c0
feat: collect portable Git and GitHub metric evidence
SHcommit Sep 1, 2026
45b3472
feat: expose adoption metrics JSON collector
SHcommit Sep 1, 2026
26021a9
fix: reject nested-quantifier ReDoS patterns in constraints: blocks s…
SHcommit Sep 1, 2026
c651658
docs: record the Windows ReDoS mitigation, note parallel Codex work e…
SHcommit Sep 1, 2026
7f09a5d
fix: harden adoption metrics evidence handling
SHcommit Sep 1, 2026
e7829d1
docs: reconcile High-priority backlog against the merged agy/version-…
SHcommit Sep 1, 2026
7fb373e
fix: complete adoption metrics source contracts
SHcommit Sep 1, 2026
e00f48c
fix: validate current check snapshots
SHcommit Sep 1, 2026
276c6a0
docs: close out adoption metrics collector
SHcommit Sep 1, 2026
f814d64
docs: record final adoption metrics verification
SHcommit Sep 1, 2026
9223bfa
docs: mark adoption metrics complete
SHcommit Sep 1, 2026
18d4662
feat: add build provenance attestation to the release workflow
SHcommit Sep 1, 2026
cf6ed62
docs: close out supply-chain attestation and add worklog
SHcommit Sep 1, 2026
dd00e37
docs: add worklogs for the Critical/High hardening pass's core decisions
SHcommit Sep 1, 2026
c59d3db
docs: record this session's hardening decisions as ADR-0012..0016
SHcommit Sep 2, 2026
2d39348
chore: bump version to 0.3.0
SHcommit Sep 2, 2026
5e8307e
fix: make resolve_from_root's containment check filesystem-independent
SHcommit Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "adr-toolkit",
"version": "0.2.1",
"version": "0.3.0",
"description": "Initialize, record, and check Architecture Decision Records by inspecting the repository and existing decisions before asking questions."
}
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ jobs:
runs-on: ubuntu-latest
# softprops/action-gh-release needs write access to create the release;
# the default GITHUB_TOKEN is read-only for repos created since Feb 2023.
# attest-build-provenance needs id-token (to mint an OIDC token for
# Sigstore's keyless signing) and attestations: write (to publish the
# resulting attestation to the repo) -- no private key to manage or
# rotate; every install/consumption path here references the git repo
# or this packaged skill folder directly (docs/adr-toolkit-audit-report.md
# §2.2 2.2), so provenance tied to the exact commit is what actually
# matters, not a signed build of something nobody downloads separately.
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand All @@ -32,7 +41,23 @@ jobs:
run: |
test "v$(cat skills/adr-toolkit/VERSION)" = "$GITHUB_REF_NAME" \
|| { echo "tag $GITHUB_REF_NAME != v$(cat skills/adr-toolkit/VERSION)"; exit 1; }
- name: Package the distributable skill
id: package
run: |
set -euo pipefail
VERSION="$(cat skills/adr-toolkit/VERSION)"
ARCHIVE="adr-toolkit-skill-v${VERSION}.tar.gz"
tar -czf "$ARCHIVE" -C skills adr-toolkit
sha256sum "$ARCHIVE" > "${ARCHIVE}.sha256"
echo "archive=$ARCHIVE" >> "$GITHUB_OUTPUT"
- name: Generate build provenance attestation
uses: actions/attest-build-provenance@v2
with:
subject-path: ${{ steps.package.outputs.archive }}
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
${{ steps.package.outputs.archive }}
${{ steps.package.outputs.archive }}.sha256
21 changes: 19 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,26 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: pip install pytest
run: pip install pytest pytest-cov
- name: Run tests
run: python -m pytest tests/unit tests/integration -v
run: python -m pytest tests/unit tests/integration -v --cov=skills/adr-toolkit/scripts --cov-branch --cov-report=term-missing --cov-fail-under=85

type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install mypy
run: pip install mypy
- name: Type-check the fully-typed core modules
run: >-
mypy
skills/adr-toolkit/scripts/core/atomic_io.py
skills/adr-toolkit/scripts/core/telemetry.py
skills/adr-toolkit/scripts/core/contracts.py
--strict

version-drift:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ adapters/antigravity/skills/adr-toolkit
# docs/superpowers/specs/ (the design docs) stay tracked; only plans/ is
# excluded. History from before this commit still has them if ever needed.
docs/superpowers/plans/

# Cross-process mutex file created by core/atomic_io.py's directory lock
# during create/exception/supersede -- a runtime artifact, not source.
.adr-toolkit.lock
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ python3 skills/adr-toolkit/scripts/adr.py check --uncommitted --dir docs/decisio
- Accepted ADRs are append-only in spirit: use supersession for changed
decisions instead of rewriting history.

## `constraints:` Block Review

An ADR's `constraints:` block is enforced by `adr.py check` against every
future diff, so a change to one is a change to the repository's policy
surface, not just prose. Until CODEOWNERS-backed independent review is
active (see "Public Repository Hygiene" below), a PR that adds or edits a
`constraints:` block requires sign-off from someone with authority over
the affected `affected_paths`, in addition to normal review. This is a
process control, not a code sandbox -- see
`docs/adr-toolkit-audit-report.md` §2.2 2.1 for why isolation isn't the
right defense here (no third-party code executes; the block is
structured policy text).

## Public Repository Hygiene

Public repository branch/tag protection is expected to enforce PRs, required
Expand Down
29 changes: 29 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,35 @@ public issue. Include:
Do not include exploit details in a public issue until a fix or mitigation is
available.

## Verifying a Release

Every `v*` release is built by `.github/workflows/release.yml` from a
tagged commit, and the workflow publishes a [GitHub Artifact
Attestation](https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)
for the packaged skill archive it attaches to the release
(`adr-toolkit-skill-vX.Y.Z.tar.gz`). This is a Sigstore-backed, keyless
signature -- no private key is held or rotated by this project -- proving
the archive was produced by this repository's own CI, from the exact
commit the release tag points to.

To verify a downloaded archive:

```bash
# Checksum: confirms the file wasn't corrupted/tampered with in transit
sha256sum -c adr-toolkit-skill-vX.Y.Z.tar.gz.sha256

# Provenance: confirms the archive was actually built by this repo's CI,
# not a look-alike release from a compromised account or a different repo
gh attestation verify adr-toolkit-skill-vX.Y.Z.tar.gz -R SHcommit/ADR-toolkit
```

Anyone consuming this repository directly (`git clone`, or an adapter's
`marketplace add`/`plugin add` pointing at the repo, which is how every
adapter installs this skill today) is verifying via Git/GitHub's own
commit and tag history rather than this archive -- the attestation is
primarily for the one path where a bare checkout doesn't happen: someone
who downloads the release archive off the GitHub Releases page directly.

## Scope

In scope:
Expand Down
2 changes: 1 addition & 1 deletion adapters/antigravity/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://antigravity.google/schemas/v1/plugin.json",
"name": "adr-toolkit",
"version": "0.2.1",
"version": "0.3.0",
"description": "Initialize, record, and check Architecture Decision Records by inspecting the repository and existing decisions before asking questions."
}
2 changes: 1 addition & 1 deletion adapters/gemini-cli/gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "adr-toolkit",
"version": "0.2.1",
"version": "0.3.0",
"description": "Initialize, record, and check Architecture Decision Records by inspecting the repository and existing decisions before asking questions."
}
59 changes: 58 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,70 @@ Lightweight human-readable summary of meaningful repository changes.

## Unreleased

## v0.3.0 (2026-09-02)

- Recorded this release's architectural decisions as ADR-0012 through
ADR-0016 (atomic writes + directory locking, the two-stage ReDoS guard,
typed result contracts + `mypy --strict`, structured JSON logging with
correlation IDs, and release artifact attestation), using the ADR
toolkit itself.
- `.github/workflows/release.yml` now packages `skills/adr-toolkit/` into a
version-named tarball, SHA-256 checksums it, and generates a Sigstore-backed
GitHub Artifact Attestation (`actions/attest-build-provenance@v2`, keyless)
for it; the tarball and checksum are attached to the GitHub Release.
`SECURITY.md` documents how to verify a downloaded release archive.
- Added `scripts/adoption_metrics.py`, a JSON-only collector for the five
enterprise adoption metrics defined in `docs/enterprise-adoption.md`:
decision lead time, review latency, supersession rate, unresolved CHECK
violations, and exception age. It combines portable ADR/exception data with
optional local Git, explicit JSONL event, CHECK snapshot, and GitHub review
evidence while reporting source coverage and incomplete-evidence warnings.
- `core/contracts.py` now covers all 16 commands' output shapes (was 2).
- `PathEscapesRootError` (added in the prior session's path-escape fix)
is now caught at all 7 call sites and reported as a structured
`PATH_ESCAPES_ROOT` error instead of falling through to a generic
internal error. All 6 domain exception classes now share a common
`AdrToolkitError` base with a stable `error_code`.
- Added a test that fails if `schemas/*.json` and the runtime validators
in `core/schema.py`/`core/exceptions.py` ever diverge -- without adding
a `jsonschema` dependency.
- `core/contracts.py` now also covers CHECK's result shape.
- Added a sanity check proving `search`/`index` don't degrade
catastrophically at 200 ADRs.
- `adr.py` now prints a one-line human-readable summary to stderr when
stderr is a real terminal (set `ADR_TOOLKIT_NO_COLOR` to suppress);
stdout's JSON contract and piped/redirected usage are unaffected.
- `--dir`/`--root` now reject a relative path that resolves outside the
given root, closing a path-escape gap.
- CI now measures branch coverage (currently 93%) and fails below 85%.
- Added a `mypy --strict` CI gate over the fully-typed core modules
(`atomic_io`, `telemetry`, the new `contracts` module of TypedDict result
shapes).
- Added `adr.py --diagnostic` (must precede the operation name) to include
an `elapsed_ms` timing field in the JSON result.
- Verified at the OS level (fork + SIGKILL) that a process killed mid-write
never leaves a torn ADR file.
- Extracted a shared adapter-manifest validator (`scripts/adapter_sdk.py`)
used by all 4 manifest-based harness adapters' tests.
- ADR and exception creation, and SUPERSEDE's two-file update, are now
atomic and race-free under concurrent invocation (file locking + write to
a temp file followed by an atomic rename).
- CHECK's author-supplied `constraints:` regex patterns now have a 0.25s
evaluation timeout on Linux/macOS, closing a ReDoS risk (Windows CI is
unaffected but not yet guarded — tracked in `improvements.md`).
- INDEX's generated decision-log README now escapes ADR titles, closing a
Markdown link-injection risk.
- Uncaught errors now log a structured, correlation-ID-tagged JSON line to
stderr (`ADR_TOOLKIT_LOG_LEVEL` controls the threshold) instead of
disappearing silently; the same correlation ID appears in the stdout
JSON error response.
- Added `.githooks/pre-push` script to block direct local `git push` to protected branches (`develop`, `master`)
and direct contributors to use Pull Requests (`feature/*` / `fix/*`).
- Added Conventional Commits PR title validation job (`pr-title-check`) to GitHub Actions workflow (`.github/workflows/test.yml`)
to enforce standard title format (`feat:`, `fix:`, `docs:`, etc.) for pull requests.
- Updated `.github/PULL_REQUEST_TEMPLATE.md` with Conventional Commits title format guide and an explicit Examples Impact checklist
requiring example updates for `feat:` and `fix:` changes while skipping non-feature PRs.
- Fixed Windows CP1252 console encoding failure (`UnicodeEncodeError: 'charmap' codec can't encode character '\u2713'`) in `scripts/verify_examples.py` and `tests/integration/test_examples.py` by replacing non-ASCII symbols with ASCII tags (`[ok]`, `[error]`), reconfiguring stdout/stderr UTF-8 streams, and setting `PYTHONIOENCODING=utf-8` in subprocess calls.
- Fixed Windows CP1252 console encoding failure (`UnicodeEncodeError: 'charmap' codec can't encode character ''`) in `scripts/verify_examples.py` and `tests/integration/test_examples.py` by replacing non-ASCII symbols with ASCII tags (`[ok]`, `[error]`), reconfiguring stdout/stderr UTF-8 streams, and setting `PYTHONIOENCODING=utf-8` in subprocess calls.
- Added untracked manifest discovery (`discover_untracked_manifests`) in `scripts/sync_version.py` to automatically prevent untracked plugin/extension manifests from being added in PRs without version/description tracking.
- Added `.pre-commit-config.yaml` for local contributor pre-commit checks and updated `CONTRIBUTING.md` with manifest governance guidelines.
- Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` tracking integrated into `scripts/sync_version.py`, expanded unit test assertions in `test_antigravity_adapter.py` (including symlink layout simulation) and `test_readme.py`, and updated `README.md` documentation.
Expand Down
Loading
Loading