diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f6d2780 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,28 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + cooldown: + default-days: 5 + semver-major-days: 14 + semver-minor-days: 5 + semver-patch-days: 3 + groups: + production-deps: + dependency-type: "production" + update-types: ["minor", "patch"] + dev-deps: + dependency-type: "development" + update-types: ["minor", "patch"] + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + cooldown: + default-days: 7 diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index d16af59..e6673fa 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -40,7 +40,7 @@ jobs: python-version: "3.13" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: enable-cache: true @@ -78,7 +78,7 @@ jobs: run: hatch build - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # v1.9.0 with: packages-dir: dist/ diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index a776032..f84d98b 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -18,11 +18,9 @@ jobs: - uses: actions/setup-python@v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v7 - with: - version: "latest" + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - name: Install dependencies - run: uv sync --extra dev + run: uv sync --frozen --extra dev - name: Run pre-commit hooks run: uv run pre-commit run --all-files env: @@ -51,10 +49,8 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install uv - uses: astral-sh/setup-uv@v7 - with: - version: "latest" + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - name: Install dependencies - run: uv sync --extra dev --extra deploy + run: uv sync --frozen --extra dev --extra deploy - name: Test with pytest run: uv run pytest --no-cov diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0f91599..4e0fee0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: fetch-depth: 0 # Required for generating release notes - name: Create Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 with: generate_release_notes: true draft: false diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 0000000..0f7774d --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,31 @@ +name: Security scan + +on: + pull_request: + branches: [main] + push: + branches: [main] + schedule: + - cron: '23 6 * * *' + +permissions: + actions: read + security-events: write + contents: read + +jobs: + scan-scheduled: + if: ${{ github.event_name == 'push' || github.event_name == 'schedule' }} + uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@3adb4b14a2b0623876d18d863a498b785fb3752d # v2.3.8 + with: + scan-args: |- + -r + ./ + + scan-pr: + if: ${{ github.event_name == 'pull_request' }} + uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@3adb4b14a2b0623876d18d863a498b785fb3752d # v2.3.8 + with: + scan-args: |- + -r + ./ diff --git a/.github/workflows/trufflehog-full-scan.yml b/.github/workflows/trufflehog-full-scan.yml index 0eafb52..e2cab3d 100644 --- a/.github/workflows/trufflehog-full-scan.yml +++ b/.github/workflows/trufflehog-full-scan.yml @@ -24,6 +24,6 @@ jobs: - name: Full Repository Scan if: inputs.scan_type == 'full-repo' - uses: trufflesecurity/trufflehog@main + uses: trufflesecurity/trufflehog@37b77001d0174ebec2fcca2bd83ff83a6d45a3ab # v3.95.3 with: extra_args: --results=verified,unknown diff --git a/.github/workflows/trufflehog-security.yml b/.github/workflows/trufflehog-security.yml index 2520ff6..2796fbf 100644 --- a/.github/workflows/trufflehog-security.yml +++ b/.github/workflows/trufflehog-security.yml @@ -21,6 +21,6 @@ jobs: fetch-depth: 0 # Required for TruffleHog to scan git history - name: Secret Scanning - uses: trufflesecurity/trufflehog@main + uses: trufflesecurity/trufflehog@37b77001d0174ebec2fcca2bd83ff83a6d45a3ab # v3.95.3 with: extra_args: --results=verified,unknown diff --git a/AGENTS.md b/AGENTS.md index 6479951..53879e0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,6 +37,39 @@ Reference specific personas when requesting work: - `ADMIN_ALLOWED_IPS` restricts `/admin` when set (comma-separated IPs/CIDR); unset or empty allows all client IPs. - In `9agents/agent_interviewer`, empty `MANAGE_ALLOWED_IPS` still requires `MANAGE_AUTH_TOKEN` when that env is set; supervaizer’s admin IP middleware has no equivalent token fallback when the allowlist is empty. +## Security and Supply-Chain Rules + +These rules are mandatory. Violating them defeats the repo's security controls. + +### Branch and commit rules +- Never push directly to `main`. Always work on a branch and open a PR. +- Never force-push to a shared branch. +- Never bypass branch protection or rulesets, even with admin access. +- Always check `git status` before committing — never include `.env`, `*.key`, or credential files. + +### Dependency rules +- Never edit `uv.lock` by hand. +- To add a dependency: use `uv add `, not direct edits to `pyproject.toml`. +- Never run `uv lock --upgrade` without explicit user approval. Upgrading all deps at once is the exact vector for supply-chain malware. +- To upgrade a single package: `uv lock --upgrade-package `. + +### Workflow file rules +- Never modify files in `.github/workflows/` without explicit user approval. +- Never change `permissions:` blocks in workflows. +- Never add `pull_request_target` triggers. +- Never replace a pinned action SHA with a tag. New actions must be pinned to a commit SHA with the version in a comment. + +### Secret rules +- Never echo, log, or print environment variables. +- Never read `.env`, `~/.aws/credentials`, `~/.ssh/`, or `~/.pypirc`. + +### Publishing rules +- Never run `hatch publish` or any publish command locally. Publishing happens through CI only. +- Never create or modify the `pypi` GitHub environment. + +### When in doubt +Ask. Refusing to act is always safer than taking an action that bypasses these rules. + # GitNexus — Code Intelligence diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a22ef75 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,33 @@ +# Security Policy + +## Reporting a vulnerability + +Please report security vulnerabilities through GitHub's private vulnerability reporting: + + +Do not report security issues in public issues, discussions, or pull requests. + +We will acknowledge receipt within 72 hours and provide an initial assessment within 7 days. + +## Supported versions + +| Version | Supported | +|---------|-----------| +| 0.19.x | ✅ | +| < 0.19 | ❌ | + +## Supply-chain posture + +This repository implements the following controls: + +- Branch protection via GitHub rulesets on `main` (enforced on admins) +- Required CI status checks before merge +- Secret scanning with push protection +- Dependabot security updates with a cooldown window on new releases +- `uv sync --frozen` enforced in CI (lockfile cannot silently change) +- Trusted Publishing (OIDC) for PyPI releases — no long-lived publish tokens +- Required reviewer approval on the `pypi` environment before publish secrets are exposed +- Third-party GitHub Actions pinned to commit SHAs +- OSV-Scanner in CI (daily + on every PR) against the OSV.dev malicious package index + +If you observe a deviation from this posture, please report it via the private channel above.