Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
47 changes: 47 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
version: 2

# Automated dependency updates (issue #443).
#
# * pip — keep the declared Python dependency floors and dev toolchain
# current. Minor/patch bumps are grouped into a single weekly PR to limit
# noise; majors open individually so breaking changes get their own review.
# * github-actions — keep workflow action references current. This is also
# how action versions stay fresh now that the workflows pin to tags rather
# than commit SHAs (see docs/security_tooling.md and issue #468).

updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: weekly
day: monday
time: "06:00"
timezone: Etc/UTC
open-pull-requests-limit: 5
groups:
python-minor-patch:
update-types:
- minor
- patch
labels:
- dependencies
commit-message:
prefix: "chore(deps)"

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
time: "06:00"
timezone: Etc/UTC
open-pull-requests-limit: 5
groups:
actions-all:
update-types:
- minor
- patch
labels:
- dependencies
commit-message:
prefix: "chore(ci)"
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ jobs:
# version in pyproject.toml. Stdlib-only; no install required.
run: python scripts/check_readme_version.py

- name: Security-policy drift check (gating, issue #691)
# Fails when SECURITY.md's supported-version table drifts from the
# package version in pyproject.toml, or when a relative link it
# references no longer resolves. Stdlib-only; no install required.
run: python scripts/check_security_policy.py

- name: Weaver-spec conformance
# Round-trip + JSON-Schema validation against the canonical contracts
# published at https://weaver-spec.dev/contracts/v0/. Gating because
Expand Down
50 changes: 50 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CodeQL

# Static security analysis for the Python sources (issue #689, umbrella #443).
# Runs the default + security-extended query packs on every PR, on pushes to
# main, and on a weekly schedule so newly published queries surface findings
# even when the code is quiet. Findings land in the repository Security tab
# (code scanning). False positives are handled via the documented exception
# process in docs/security_tooling.md (issue #692).

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Monday 07:00 UTC. Off-hours, just after the weekly scorecard/benchmark
# crons, low contention with the gating CI job.
- cron: "0 7 * * 1"

permissions:
contents: read

concurrency:
group: codeql-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
analyze:
name: Analyze (python)
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
# Required for CodeQL to upload results to the code-scanning dashboard.
security-events: write
contents: read
steps:
- uses: actions/checkout@v4

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python
# ``security-extended`` adds the broader security query suite on top
# of the default pack; pure-Python project, so no build step.
queries: security-extended

- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:python"
61 changes: 61 additions & 0 deletions .github/workflows/ossf-scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: OpenSSF Scorecard

# OpenSSF Scorecard supply-chain health analysis (issue #552, umbrella #443).
#
# Distinct from the *benchmark* scorecard regenerated by
# scorecard-weekly.yml — that one measures routing recall / token savings.
# This workflow runs the OpenSSF Scorecard checks (branch protection, token
# permissions, pinned dependencies, dangerous workflows, maintained, etc.),
# uploads the SARIF to the code-scanning dashboard, and publishes results so
# the README badge resolves.
#
# Applying for the OpenSSF Best Practices badge is a tracked manual step — see
# docs/security_tooling.md.

on:
branch_protection_rule:
push:
branches: [main]
schedule:
# Monday 08:00 UTC.
- cron: "0 8 * * 1"

permissions:
contents: read

jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
# Upload the results to the code-scanning dashboard.
security-events: write
# Publish results to the OpenSSF REST API so the README badge resolves.
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@v2
with:
results_file: results.sarif
results_format: sarif
# publish_results enables the public badge endpoint at
# api.securityscorecards.dev (see the README badge).
publish_results: true

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: scorecard-results
path: results.sarif
retention-days: 5

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
83 changes: 83 additions & 0 deletions .github/workflows/pip-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: pip-audit

# Dependency vulnerability scan (issue #689, umbrella #443).
#
# Policy (documented in docs/security_tooling.md, issue #692):
# * The CORE runtime dependency set is GATING — a known-vulnerable advisory
# against a core dependency fails the job, because adopters put
# contextweaver in the data path between agents and tools.
# * The DEV/test extra is report-only (continue-on-error): it pulls a large
# transitive tree (crewai, mem0ai, fastmcp, langgraph, langchain-core) that
# would otherwise make the gate noisy and flaky. Findings are still printed
# for triage and recorded in the job summary.
#
# Runs on PRs that touch dependency metadata, on pushes to main, and weekly so
# newly published advisories surface against an otherwise-quiet tree.

on:
push:
branches: [main]
paths:
- "pyproject.toml"
- ".github/workflows/pip-audit.yml"
pull_request:
paths:
- "pyproject.toml"
- ".github/workflows/pip-audit.yml"
schedule:
# Monday 07:30 UTC, after CodeQL.
- cron: "30 7 * * 1"

permissions:
contents: read

concurrency:
group: pip-audit-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
audit-core:
name: Audit core dependencies (gating)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install core package and pip-audit
run: |
python -m pip install --upgrade pip
pip install -e .
pip install pip-audit

- name: Audit installed environment (gating)
# No --ignore-vuln entries today. Document any future exception here
# with the advisory id and a link to its tracking issue, per the
# exception process in docs/security_tooling.md.
run: pip-audit --progress-spinner off

audit-dev:
name: Audit dev extra (report-only)
runs-on: ubuntu-latest
timeout-minutes: 20
continue-on-error: true
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install dev extra and pip-audit
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install pip-audit

- name: Audit installed environment (report-only)
run: pip-audit --progress-spinner off
56 changes: 55 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,57 @@ permissions:
contents: read

jobs:
verify:
# Release-integrity gate (issue #468). A release publishes straight to PyPI
# and the MCP Registry over OIDC, so this job is the last chance to catch a
# mis-tagged or untested release before it is immutable on PyPI. It proves:
# 1. the release tag matches the package version (no ``v0.16.0`` tag
# shipping a ``0.15.0`` artifact);
# 2. the package builds and its metadata passes ``twine check``;
# 3. the gating test suite is green at the released commit.
# ``publish`` depends on this job, so a red gate blocks the upload.
name: Verify release integrity
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Check release tag matches package version
# ``GITHUB_REF_NAME`` is the tag the release was cut from (``vX.Y.Z``).
# The package version is the single source of truth in pyproject.toml.
run: |
tag="${GITHUB_REF_NAME}"
version="$(python scripts/check_readme_version.py --print-version)"
if [ "$tag" != "v$version" ]; then
echo "::error::Release tag '$tag' does not match package version 'v$version' (pyproject.toml)." >&2
exit 1
fi
echo "Release tag '$tag' matches package version 'v$version'."

- name: Install package and test/build tooling
run: pip install -e ".[dev]" build twine

- name: Pre-publish test suite (gating)
run: pytest -q

- name: Build and check distribution metadata
run: |
python -m build
twine check dist/*

publish:
needs: verify
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write # Required for Trusted Publisher (OIDC)
id-token: write # Required for Trusted Publisher (OIDC)
contents: read
attestations: write # Required to attach build-provenance attestations (issue #690)
steps:
- uses: actions/checkout@v4

Expand All @@ -27,6 +73,14 @@ jobs:
- name: Build sdist and wheel
run: python -m build

- name: Attest build provenance
# Generates a signed, verifiable provenance attestation for each built
# artifact (issue #690). Verifiable later with ``gh attestation verify
# <file> --repo dgenio/contextweaver``.
uses: actions/attest-build-provenance@v2
Comment thread
dgenio marked this conversation as resolved.
Outdated
with:
subject-path: "dist/*"

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ make test # python -m pytest --cov=contextweaver --cov-report=term-missing -
make example # run all example scripts (includes architectures via the umbrella target)
make architectures # run reference architecture scripts under examples/architectures/
make demo # python -m contextweaver demo
make ci # fmt + lint + type + test + drift-check + module-size-check + doc-snippets-check + readme-version-check + example + demo
make ci # fmt + lint + type + test + drift-check + module-size-check + doc-snippets-check + readme-version-check + security-policy-check + example + demo
make docs # mkdocs build --clean (docs site)
make docs-serve # mkdocs serve (live preview)
make benchmark # run benchmark harness (non-gating; writes benchmarks/results/latest.json)
Expand All @@ -236,6 +236,7 @@ make sweep-scoring # weight sweep for ScoringConfig (#214); writes benchmarks
make context-rot # render the context-rot demo: benchmarks/results/context_rot.json + docs/assets/context_rot.svg (#349)
make context-rot-check # verify context_rot.svg matches its committed JSON (gating in CI; exits non-zero on drift)
make readme-version-check # verify README version references match pyproject.toml (gating in CI; #347)
make security-policy-check # verify SECURITY.md supported series + links match pyproject.toml (gating in CI; #691)
make llms # regenerate llms.txt and llms-full.txt from canonical docs
make llms-check # verify llms.txt and llms-full.txt are up to date (gating in CI; #389)
make weaver-conformance # round-trip + JSON-Schema validate the weaver-spec adapter (CI gating, fetches schemas)
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- **Supply-chain & security CI hardening (#443, #689, #690, #691, #692, #468, #552).**
A coordinated security-posture pass under the supply-chain hardening umbrella (#443):
- **CodeQL** code scanning (`.github/workflows/codeql.yml`) with the
`security-extended` query pack, on PR, `main`, and a weekly schedule (#689).
- **pip-audit** dependency scanning (`.github/workflows/pip-audit.yml`):
gating on the core runtime dependency set, report-only for the heavier dev
extra (#689).
- **OpenSSF Scorecard** analysis (`.github/workflows/ossf-scorecard.yml`)
with results published to code scanning and a README badge; the OpenSSF
Best Practices badge application is tracked as a manual step (#552).
- **Dependabot** (`.github/dependabot.yml`) weekly `pip` and `github-actions`
updates, grouped to limit noise (#443).
- **Release-integrity gate** in `publish.yml` (#468): a `verify` job asserts
the release tag matches the `pyproject.toml` version, runs the test suite,
and `twine check`s the built distribution before the publish job runs.
- **Build-provenance attestations** for released artifacts via
`actions/attest-build-provenance` (#690).
- **`security-policy-check`** gate (`scripts/check_security_policy.py`, wired
into `make ci` and `ci.yml`): fails when `SECURITY.md`'s supported-version
table drifts from the package version or links a missing doc. Refreshed the
supported series to `0.16.x` (#691).
- **Security tooling runbook** (`docs/security_tooling.md`) documenting the
triage SLA, ownership, and the false-positive exception process (#692).
- `scripts/check_readme_version.py` gained a `--print-version` flag so the
release-integrity gate reads the package version through the same single
source of truth as the drift guard.

## [0.16.0] - 2026-06-21

### Added
Expand Down
Loading
Loading