name: CI
on:
push:
branches:
- main
- develop
pull_request:
permissions: read-all
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
COREASON_CLA_ACCEPTED: "yes"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-and-audit:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- name: Pre-Flight Workspace Purity
run: sudo chown -R $(whoami):$(whoami) ${{ github.workspace }} || true
- name: Harden Runner (Endpoint Network Security)
uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with:
fetch-depth: 0
fetch-tags: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b with:
enable-cache: true
python-version: '3.14'
- name: Extract versions and Patch PyProject
run: |
python -c "
import os, re
with open('pyproject.toml', 'r', encoding='utf-8') as f:
content = f.read()
m_match = re.search(r'coreason-manifest[>=]=([0-9]+\.[0-9]+\.[0-9]+)', content)
if not m_match:
print('Failed to extract coreason-manifest version from pyproject.toml')
exit(1)
m_ver = 'v' + m_match.group(1)
# coreason-urn-authority is optional (removed in Rust refactor)
u_match = re.search(r'coreason-urn-authority[>=~]+([0-9]+\.[0-9]+\.[0-9]+)', content)
u_ver = 'v' + u_match.group(1) if u_match else None
github_env = os.environ.get('GITHUB_ENV')
if github_env:
with open(github_env, 'a', encoding='utf-8') as ge:
ge.write(f'MANIFEST_VERSION={m_ver}\n')
if u_ver:
ge.write(f'URN_AUTHORITY_VERSION={u_ver}\n')
content = content.replace('coreason-manifest = { git = \"https://github.com/CoReason-AI/coreason-manifest.git\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
content = content.replace('coreason-manifest = { path = \"../coreason-manifest\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
if u_ver:
content = content.replace('coreason-urn-authority = { git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('coreason-urn-authority = { path = \"../coreason-urn-authority\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('prerelease = \"allow\"', f'prerelease = \"allow\"\noverride-dependencies = [\"coreason-manifest @ git+https://github.com/CoReason-AI/coreason-manifest.git@{m_ver}\"]')
with open('pyproject.toml', 'w', encoding='utf-8') as f:
f.write(content)
"
uv lock
shell: bash
- name: Install dependencies
run: uv sync --all-extras --dev --frozen
shell: bash
- name: Check code (Ruff)
run: uv run ruff check .
shell: bash
- name: Format check (Ruff)
run: uv run ruff format --check .
shell: bash
- name: Typecheck (Mypy)
run: uv run mypy src/ tests/
shell: bash
- name: Audit dependencies (Deptry)
run: uv run deptry src/
shell: bash
- name: Build docs
run: uv run zensical build
shell: bash
- name: Substrate Purity Verification
run: git clean -xfd -e .venv -e .uv_cache
test-ubuntu:
needs: [lint-and-audit]
if: always() && needs.lint-and-audit.result == 'success'
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
python-version: ["3.14", "3.14t"]
steps:
- name: Pre-Flight Workspace Purity
run: sudo chown -R $(whoami):$(whoami) ${{ github.workspace }} || true
- name: Harden Runner (Endpoint Network Security)
uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with:
fetch-depth: 0
fetch-tags: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Extract versions and Patch PyProject
run: |
python -c "
import os, re
with open('pyproject.toml', 'r', encoding='utf-8') as f:
content = f.read()
m_match = re.search(r'coreason-manifest[>=]=([0-9]+\.[0-9]+\.[0-9]+)', content)
if not m_match:
print('Failed to extract coreason-manifest version from pyproject.toml')
exit(1)
m_ver = 'v' + m_match.group(1)
# coreason-urn-authority is optional (removed in Rust refactor)
u_match = re.search(r'coreason-urn-authority[>=~]+([0-9]+\.[0-9]+\.[0-9]+)', content)
u_ver = 'v' + u_match.group(1) if u_match else None
github_env = os.environ.get('GITHUB_ENV')
if github_env:
with open(github_env, 'a', encoding='utf-8') as ge:
ge.write(f'MANIFEST_VERSION={m_ver}\n')
if u_ver:
ge.write(f'URN_AUTHORITY_VERSION={u_ver}\n')
content = content.replace('coreason-manifest = { git = \"https://github.com/CoReason-AI/coreason-manifest.git\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
content = content.replace('coreason-manifest = { path = \"../coreason-manifest\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
if u_ver:
content = content.replace('coreason-urn-authority = { git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('coreason-urn-authority = { path = \"../coreason-urn-authority\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('prerelease = \"allow\"', f'prerelease = \"allow\"\noverride-dependencies = [\"coreason-manifest @ git+https://github.com/CoReason-AI/coreason-manifest.git@{m_ver}\"]')
with open('pyproject.toml', 'w', encoding='utf-8') as f:
f.write(content)
"
uv lock
shell: bash
- name: Configure free-threading execution
if: matrix.python-version == '3.14t'
run: echo "PYTHON_GIL=0" >> "$GITHUB_ENV"
shell: bash
- name: Install dependencies
run: uv sync --all-extras --dev --frozen
shell: bash
- name: Run tests
run: uv run pytest --cov=src --cov-report=xml
shell: bash
- name: Upload coverage to Codecov
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
verbose: true
- name: Substrate Purity Verification
run: git clean -xfd -e .venv -e .uv_cache
test-extended:
needs: [test-ubuntu]
if: always() && needs.test-ubuntu.result == 'success'
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
matrix:
os: [windows-latest, macos-latest]
python-version: ["3.14", "3.14t"]
exclude:
- os: windows-latest
python-version: "3.14t"
- os: macos-latest
python-version: "3.14t"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with:
fetch-depth: 0
fetch-tags: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Extract versions and Patch PyProject
run: |
python -c "
import os, re
with open('pyproject.toml', 'r', encoding='utf-8') as f:
content = f.read()
m_match = re.search(r'coreason-manifest[>=]=([0-9]+\.[0-9]+\.[0-9]+)', content)
if not m_match:
print('Failed to extract coreason-manifest version from pyproject.toml')
exit(1)
m_ver = 'v' + m_match.group(1)
# coreason-urn-authority is optional (removed in Rust refactor)
u_match = re.search(r'coreason-urn-authority[>=~]+([0-9]+\.[0-9]+\.[0-9]+)', content)
u_ver = 'v' + u_match.group(1) if u_match else None
github_env = os.environ.get('GITHUB_ENV')
if github_env:
with open(github_env, 'a', encoding='utf-8') as ge:
ge.write(f'MANIFEST_VERSION={m_ver}\n')
if u_ver:
ge.write(f'URN_AUTHORITY_VERSION={u_ver}\n')
content = content.replace('coreason-manifest = { git = \"https://github.com/CoReason-AI/coreason-manifest.git\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
content = content.replace('coreason-manifest = { path = \"../coreason-manifest\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
if u_ver:
content = content.replace('coreason-urn-authority = { git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('coreason-urn-authority = { path = \"../coreason-urn-authority\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('prerelease = \"allow\"', f'prerelease = \"allow\"\noverride-dependencies = [\"coreason-manifest @ git+https://github.com/CoReason-AI/coreason-manifest.git@{m_ver}\"]')
with open('pyproject.toml', 'w', encoding='utf-8') as f:
f.write(content)
"
uv lock
shell: bash
- name: Configure free-threading execution
if: matrix.python-version == '3.14t'
run: echo "PYTHON_GIL=0" >> "$GITHUB_ENV"
shell: bash
- name: Install dependencies
run: uv sync --all-extras --dev --frozen
shell: bash
- name: Run tests
run: uv run pytest --cov=src --cov-report=xml
shell: bash
reproducible-builds:
name: Determinism Verification
needs: [test-ubuntu, test-extended]
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Harden Runner (Endpoint Network Security)
uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with:
fetch-depth: 0
fetch-tags: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b with:
enable-cache: true
python-version: "3.14"
- name: Extract versions and Patch PyProject
run: |
python -c "
import os, re
with open('pyproject.toml', 'r', encoding='utf-8') as f:
content = f.read()
m_match = re.search(r'coreason-manifest[>=]=([0-9]+\.[0-9]+\.[0-9]+)', content)
if not m_match:
print('Failed to extract coreason-manifest version from pyproject.toml')
exit(1)
m_ver = 'v' + m_match.group(1)
# coreason-urn-authority is optional (removed in Rust refactor)
u_match = re.search(r'coreason-urn-authority[>=~]+([0-9]+\.[0-9]+\.[0-9]+)', content)
u_ver = 'v' + u_match.group(1) if u_match else None
github_env = os.environ.get('GITHUB_ENV')
if github_env:
with open(github_env, 'a', encoding='utf-8') as ge:
ge.write(f'MANIFEST_VERSION={m_ver}\n')
if u_ver:
ge.write(f'URN_AUTHORITY_VERSION={u_ver}\n')
content = content.replace('coreason-manifest = { git = \"https://github.com/CoReason-AI/coreason-manifest.git\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
content = content.replace('coreason-manifest = { path = \"../coreason-manifest\" }', f'coreason-manifest = {{ git = \"https://github.com/CoReason-AI/coreason-manifest.git\", tag = \"{m_ver}\" }}')
if u_ver:
content = content.replace('coreason-urn-authority = { git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('coreason-urn-authority = { path = \"../coreason-urn-authority\" }', f'coreason-urn-authority = {{ git = \"https://github.com/CoReason-AI/coreason-urn-authority.git\", tag = \"{u_ver}\" }}')
content = content.replace('prerelease = \"allow\"', f'prerelease = \"allow\"\noverride-dependencies = [\"coreason-manifest @ git+https://github.com/CoReason-AI/coreason-manifest.git@{m_ver}\"]')
with open('pyproject.toml', 'w', encoding='utf-8') as f:
f.write(content)
"
uv lock
shell: bash
- name: Build wheel (attempt 1)
run: |
export SOURCE_DATE_EPOCH=315532800
uv build --out-dir dist1
sha256sum dist1/*.whl | tee /tmp/hash1.txt
shell: bash
- name: Build wheel (attempt 2)
run: |
export SOURCE_DATE_EPOCH=315532800
uv build --out-dir dist2
sha256sum dist2/*.whl | tee /tmp/hash2.txt
shell: bash
- name: Verify deterministic build
run: |
HASH1=$(awk '{print $1}' /tmp/hash1.txt)
HASH2=$(awk '{print $1}' /tmp/hash2.txt)
echo "Build 1 SHA256: $HASH1"
echo "Build 2 SHA256: $HASH2"
if [ "$HASH1" != "$HASH2" ]; then
echo "::error::CRITICAL: Non-deterministic build detected! Hashes do not match."
exit 1
fi
echo "✅ Deterministic build verified. SHA256: $HASH1"
shell: bash