Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
56 changes: 45 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,45 @@ on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read
id-token: none

jobs:
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]

steps:
- name: Harden runner
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Setup Python
uses: actions/setup-python@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: ${{ matrix.python-version }}

- name: Install
- name: Guard supply-chain invariants
run: python scripts/check_workflows.py

- name: Install hash-locked dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
python -m pip install --require-hashes -r requirements-dev.txt
python -m pip install --no-deps -e .

- name: Pre-commit (lint + format + hygiene)
env:
Expand All @@ -38,18 +55,13 @@ jobs:
FROM_REF="${{ github.event.before }}"
TO_REF="${{ github.sha }}"
fi
# Some event refs may not exist in shallow/partial clones.
# If either commit is unavailable, fall back to all-files mode.
if ! git cat-file -e "${FROM_REF}^{commit}" 2>/dev/null || ! git cat-file -e "${TO_REF}^{commit}" 2>/dev/null; then
echo "Pre-commit refs unavailable in checkout (from=$FROM_REF to=$TO_REF); running all-files."
pre-commit run --show-diff-on-failure --all-files
exit $?
fi
if echo "$FROM_REF" | grep -Eq '^0+$'; then
echo "Running pre-commit on all files (no valid base ref)"
pre-commit run --show-diff-on-failure --all-files
else
echo "Running pre-commit from $FROM_REF to $TO_REF"
pre-commit run --show-diff-on-failure --from-ref "$FROM_REF" --to-ref "$TO_REF"
fi

Expand All @@ -64,3 +76,25 @@ jobs:

- name: Run mypy
run: mypy ori_sdk

- name: Audit pinned Python dependencies
run: |
python -m pip_audit -r requirements.txt
python -m pip_audit -r requirements-dev.txt

- name: Generate SBOM
if: matrix.python-version == '3.12'
run: |
python -m cyclonedx_py requirements requirements.txt \
--pyproject pyproject.toml \
--output-reproducible \
--of JSON \
-o sbom-sdk.json

- name: Upload SBOM
if: matrix.python-version == '3.12'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: sbom-sdk
path: sbom-sdk.json
if-no-files-found: error
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ default_install_hook_types: [pre-commit, pre-push, commit-msg]
repos:
# ── Ruff: lint + format ──────────────────────────────────────────────────────
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.9
rev: c60c980e561ed3e73101667fe8365c609d19a438 # v0.15.9
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand Down Expand Up @@ -75,7 +75,7 @@ repos:

# ── Basic file hygiene ───────────────────────────────────────────────────────
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # v5.0.0
hooks:
- id: trailing-whitespace
exclude: \.md$
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
48 changes: 48 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,51 @@ pre-commit run --all-files
pytest -q
mypy ori_sdk
```

---

## Supply Chain Security Invariants

These rules apply to every AI coding agent modifying this repository. Violating
these rules can compromise the SDK that is embedded in systems controlling physical hardware.

1. Never add `pull_request_target` workflows that checkout or execute untrusted
PR code. Use `pull_request` for fork PR workflows.

2. Every GitHub Actions workflow must declare explicit least-privilege
permissions. Normal CI uses `contents: read` and `id-token: none`.

3. `id-token: write` is allowed only in a dedicated release job in `release.yml`.
It must never appear in `ci.yml`.

4. Release jobs must never restore dependency caches (`actions/cache`, package
manager caches, or setup action cache flags). Cache poisoning was a key part
of the TanStack May 2026 supply-chain attack.

5. GitHub Actions must be pinned to full commit SHAs. Mutable tags such as
`@v4`, `@v5`, `@main`, and `@master` are forbidden. Add a human-readable
version comment next to each SHA.

6. Never download and execute remote scripts in CI without hash or signature
verification. `curl URL | bash` and equivalent patterns are forbidden.

7. Python installs in CI must use hash-locked requirements files with
`--require-hashes`. Do not use `pip install -e '.[dev]'` to resolve
dependencies in CI.

8. Device deployment must install from signed artifacts or a signed wheelhouse.
Production deployment must not resolve dependencies live from public registries.

9. Valid provenance does not imply safe code. The TanStack May 2026 incident
produced malicious packages through legitimate CI/OIDC pathways. For Ori,
Tier C/D skill review gates and runtime sandboxing remain mandatory
regardless of provenance or author reputation.

10. Run `scripts/check_workflows.py` before merging workflow or pre-commit
configuration changes. The script fails on `pull_request_target`, mutable
action refs, unauthorized `id-token: write`, remote script execution
patterns, and remote pre-commit hooks not pinned to full commit SHAs.

11. Ed25519 signing implementations that must interoperate with the runtime use
`cryptography`, not PyNaCl. Alignment with ori-skills-hub and ori-runtime is
required — all three repos use `cryptography` for Ed25519 operations.
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ dependencies = ["PyYAML>=6.0.1,<7"]

[project.optional-dependencies]
dev = [
"pytest>=8.3,<9",
"pytest>=9.0.3", # CVE-2025-71176 fixed in 9.0.3
"mypy>=1.11,<2",
"ruff>=0.6,<1",
"pre-commit>=3.7,<4",
"pip-audit>=2.7",
"cyclonedx-bom>=4.0",
]

[tool.setuptools.packages.find]
Expand Down
7 changes: 7 additions & 0 deletions requirements-dev.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-r requirements.txt
pytest>=9.0.3 # CVE-2025-71176 fixed in 9.0.3
mypy>=1.11,<2
ruff>=0.6,<1
pre-commit>=3.7,<4
pip-audit>=2.7
cyclonedx-bom>=4.0
Loading
Loading