Skip to content

chore(release): reconcile platform manifest with flow 1.34.0, privacy 1.0.4 #229

chore(release): reconcile platform manifest with flow 1.34.0, privacy 1.0.4

chore(release): reconcile platform manifest with flow 1.34.0, privacy 1.0.4 #229

name: Platform manifest and source boundary
# Validates platform-manifest.json against the real published artifacts
# (PyPI, status.json) and enforces the open-core source boundary.
# See docs/platform-manifest.md and scripts/check_source_boundary.py.
on:
pull_request:
branches:
- '**'
push:
branches:
- main
schedule:
# DAILY drift check. The manifest goes stale when a component releases in
# ANOTHER repository, so no commit
# lands here and only the schedule can notice. This was weekly, which
# meant up to seven days of serving wrong sha256 digests from
# raw.githubusercontent; flow 1.24.0 published on 2026-07-27 and the
# manifest still advertised 1.23.0's digests. One small stdlib-only job
# costs seconds a day.
- cron: '17 6 * * *'
workflow_dispatch:
# Receiver for a component repository to announce its release immediately
# rather than waiting for the daily sweep.
#
# NOT YET WIRED: as of 2026-08-18 no component repository sends this. No
# component has a dispatch step in its release
# workflow, so the daily cron above is in practice the ONLY thing that
# notices a component release. That is how flow 1.25.0 and 1.25.1 published
# on 2026-07-27 after the manifest was regenerated at 15:42 that day and the
# manifest went stale again within hours, red on every PR until someone
# regenerated by hand.
#
# The sending side would be one step in each component's release workflow:
# gh api repos/OpenAdaptAI/OpenAdapt/dispatches -f event_type=component-released
# It cannot use that repository's default GITHUB_TOKEN, which is scoped to
# its own repository; cross-repository dispatch needs a token with `contents:
# write` on OpenAdaptAI/OpenAdapt stored as a secret in each component repo.
# Provisioning that secret is a credential decision, not a code change, so it
# is tracked outside this file rather than half-implemented here.
#
# Note that even a wired sender only makes DETECTION immediate. Repair stays
# manual: this workflow validates and files an issue, it does not regenerate.
# Auto-opening a fix PR is currently impossible anyway -- Actions is not
# permitted to create pull requests in this repository
# (`can_approve_pull_request_reviews: false`), so such a job would be
# permanently red rather than helpful.
repository_dispatch:
types: [component-released]
concurrency:
group: >-
platform-manifest-${{ github.event_name }}-${{
github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
validate-platform-manifest:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
# Cheapest decisive check first: structure, signature honesty, and
# repo agreement need no network and cannot be flaky.
- name: Validate platform manifest structure (offline)
run: python scripts/validate_platform_manifest.py --offline
# Standard library only: no dependency install, no lockfile, no cache.
- name: Validate platform manifest against published artifacts
env:
GITHUB_TOKEN: ${{ github.token }}
run: python scripts/validate_platform_manifest.py
- name: Prove the drift guard fails when it should
# The daily/dispatched production check is intentionally stdlib-only.
# This characterization suite belongs on source changes, not every
# remote drift probe, so scheduled checks stay fast and network-light.
if: github.event_name == 'pull_request' || github.event_name == 'push'
run: |
python -m pip install --quiet 'pytest>=8.0.0'
python -m pytest \
tests/test_platform_manifest_drift.py \
tests/test_platform_version_display.py -q
report-manifest-drift:
# A red scheduled run in a repository nobody has open is not a signal.
# The 2026-07-27 drift DID turn the cron red and still shipped, because
# main was already red from the previous night's release. File an issue
# so drift has an owner and a paper trail instead of a stale red dot.
needs: validate-platform-manifest
if: >-
${{ always() && needs.validate-platform-manifest.result == 'failure' &&
(github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
github.event_name == 'repository_dispatch') }}
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: File or update the manifest drift issue
env:
GH_TOKEN: ${{ github.token }}
run: |
TITLE="platform-manifest.json has drifted from the published releases"
BODY="The scheduled platform manifest check failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
\`platform-manifest.json\` is served publicly from raw.githubusercontent and is OpenAdapt's only cryptographic claim about the current release. While it is stale, anyone verifying a downloaded wheel or sdist against it fails.
Fix: \`python scripts/generate_platform_manifest.py && python scripts/validate_platform_manifest.py\`, then open a PR."
EXISTING=$(gh issue list --repo "${{ github.repository }}" --state open \
--search "in:title \"$TITLE\"" --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
gh issue comment "$EXISTING" --repo "${{ github.repository }}" --body "$BODY"
else
gh issue create --repo "${{ github.repository }}" --title "$TITLE" --body "$BODY"
fi
check-source-boundary:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
# The guard reads its rules from source-policy.public.json (rendered from
# the canonical private manifest) and fails closed when that file is
# missing or incomplete. Stdlib only: no dependency install.
- name: Check open-core source boundary
run: python scripts/check_source_boundary.py
# Prove the guard still blocks what it blocked before the rules moved out
# of the script, and that it fails closed without them.
- name: Prove the boundary guard fails when it should
if: github.event_name == 'pull_request' || github.event_name == 'push'
run: |
python -m pip install --quiet 'pytest>=8.0.0'
python -m pytest tests/test_source_boundary.py -q