|
46051
|
26761
|
116
|
5
|
4c2cfd53802075ca008755d01e8924cd52709e59
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
# Compose parses all services even for --no-deps redpanda and down.
# These unused service values deliberately cannot start a runtime.
PLATFORM_DEPLOYMENT_ENV: test
PLATFORM_RUNTIME_IMAGE: enterprise-platform/runtime:ci-not-started
PLATFORM_RUNTIME_DATABASE_RUNTIME_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_DATABASE_SYSTEM_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_REDIS_URL: redis://127.0.0.1:1/15
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and provision every module acceptance database
run: |
pnpm runtime:build:modules
node governance/prepare-module-databases.mjs
- name: Prepare mainline fixtures and verify identity ordinary-role databases
run: |
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Build isolated MinIO from pinned upstream source
run: docker build -t enterprise-platform/test-minio:a6c538c5 stack/test-minio
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Registry admission and central audit recovery
run: pnpm check:registry-admission
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Configuration snapshots, tenant isolation and remote SDK acceptance
run: pnpm acceptance:configuration
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Identity signing against isolated OpenBao Transit
run: pnpm identity:check:transit
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload workbench browser diagnostics
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-workbench-browser-${{ env.CANDIDATE_TAG }}
path: /tmp/platform-workbench-ui-*/
retention-days: "7"
- if: always()
name: Upload runtime and UI evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/configuration-runtime.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
reports/registry-admission.latest.json
reports/identity-transit.latest.json
reports/scope-http.latest.json
reports/scope-fact-sla.latest.json
reports/machine-revocation-sla.latest.json
reports/credential-m1-sla.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
37513
|
4
|
1793522141
|
1793522141
|
1793521755
|
1793522141
|
|
1
|
|
0
|
Edit
Delete
|
|
46052
|
26761
|
116
|
5
|
4c2cfd53802075ca008755d01e8924cd52709e59
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; shared runtime identity fixture dependencies)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Build shared identity fixture dependencies from this checkout
run: |
pnpm --dir runtime install --frozen-lockfile --filter @juhai/module-identity... --filter @juhai/client-identity --filter api-nestjs
pnpm --dir runtime --filter @juhai/module-identity prisma:generate
pnpm --dir runtime exec turbo run build --filter=@juhai/module-identity... --filter=@juhai/client-identity...
pnpm --dir identity --filter api-nestjs exec node -e "require('node:assert/strict').strictEqual(require('@juhai/module-kit'), require('../../../runtime/modules/kit'))"
- name: Provision ordinary owner for the isolated identity test database
run: |
psql "${DATABASE_URL%%\?*}" -v ON_ERROR_STOP=1 <<'SQL'
CREATE ROLE enterprise_idp_ci_rt LOGIN PASSWORD 'ci-test-only' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;
ALTER DATABASE enterprise_idp_ci OWNER TO enterprise_idp_ci_rt;
ALTER SCHEMA public OWNER TO enterprise_idp_ci_rt;
SQL
echo 'DATABASE_URL=postgresql://enterprise_idp_ci_rt:ci-test-only@127.0.0.1:5432/enterprise_idp_ci?schema=public' >> "$GITHUB_ENV"
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (single NestJS host, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (single NestJS host)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
37514
|
4
|
1793522143
|
1793522143
|
1793521755
|
1793522143
|
|
1
|
|
0
|
Edit
Delete
|
|
46053
|
26761
|
116
|
5
|
4c2cfd53802075ca008755d01e8924cd52709e59
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: https://github.com/sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
37515
|
4
|
1793522145
|
1793522145
|
1793521755
|
1793522145
|
|
1
|
|
0
|
Edit
Delete
|
|
46054
|
26761
|
116
|
5
|
4c2cfd53802075ca008755d01e8924cd52709e59
|
0
|
Release candidate verification + manifest
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${GITHUB_RUN_ATTEMPT}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Download image and full SBOM evidence for the same candidate
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-image-${{ env.CANDIDATE_TAG }}
path: reports
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ needs.image.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity","image"]...
|
["ubuntu-latest"]
|
37516
|
2
|
1793522147
|
1793522194
|
1793521755
|
1793522195
|
|
1
|
|
0
|
Edit
Delete
|
|
46055
|
26762
|
116
|
5
|
92c09a09fe3dd2c949f933fc1871f0c00ef65efd
|
0
|
prepare
|
1
|
name: Gitea private upgrade preparation
"on name: Gitea private upgrade preparation
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-upgrade-stage.yml]
workflow_dispatch:
jobs:
prepare:
name: prepare
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Preserve reproduced baseline and prepare isolated compatibility analysis
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, json, os, pathlib, re, shutil, socket, sqlite3, subprocess, time
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
source=pathlib.Path('/root/gitea-src')
def sha(p):
h=hashlib.sha256()
with open(p,'rb') as f:
for b in iter(lambda:f.read(1024*1024),b''):h.update(b)
return h.hexdigest()
if sha('/usr/local/bin/gitea')!='640efd1256fe5ace902a1185bd6fdedd063ec1eec08422aceded8cc9559a8dc9':raise RuntimeError('INSTALLED_BINARY_CHANGED')
def source_files():
paths=[]
for root,dirs,files in os.walk(source):
dirs[:]=sorted(d for d in dirs if d not in ['.git','node_modules','.cache','.secrets','.evidence-private'])
for name in sorted(files):
if name.startswith('.env') or name.endswith(('.key','.pem')):continue
p=pathlib.Path(root)/name
if not p.is_symlink() and p.is_file():paths.append(p)
return paths
def fingerprint(paths):
h=hashlib.sha256()
for p in paths:h.update(str(p.relative_to(source)).encode()+b'\0'+bytes.fromhex(sha(p)))
return h.hexdigest()
paths=source_files();before=fingerprint(paths)
if before!='a5534f2aa03220a02efecac6753f0edcb99db7e8a3da323a1bac3390e2793d74':raise RuntimeError('REPRODUCED_SOURCE_CHANGED')
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
if shutil.disk_usage(base).free<40*1024**3:raise RuntimeError('STAGING_FREE_SPACE_REQUIRED')
work=base/('stage-'+runid);work.mkdir(mode=0o700)
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
report={'kind':'GiteaUpgradePrivatePreparation','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'privateWorkspace':str(work),'liveServiceChanges':False,'liveDatabaseWrites':False,'fullConsistentBackup':False,'sourceFingerprint':before}
def emit(stage):
report['stage']=stage;print('GITEA_UPGRADE_PREPARATION_JSON '+json.dumps(report,separators=(',',':')),flush=True)
def git(args,cwd=source,timeout=300):
return subprocess.run(['git','-c','credential.helper=','-c','core.askPass=','-c','http.extraHeader=','-c','core.hooksPath=/dev/null',*args],cwd=cwd,env=env,stdin=subprocess.DEVNULL,capture_output=True,timeout=timeout)
emit('PREPARING')
snapshot=work/'baseline-source';snapshot.mkdir(mode=0o700)
for p in paths:
target=snapshot/p.relative_to(source);target.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(p,target)
shutil.copy2('/usr/local/bin/gitea',work/'gitea.previous')
bundle=git(['bundle','create',str(work/'baseline.bundle'),'HEAD'])
if bundle.returncode:raise RuntimeError('SOURCE_BUNDLE_FAILED')
patch=git(['diff','--binary','HEAD'])
if patch.returncode:raise RuntimeError('SOURCE_PATCH_FAILED')
(work/'baseline-working.patch').write_bytes(patch.stdout)
if fingerprint(paths)!=before:raise RuntimeError('SOURCE_CHANGED_DURING_SNAPSHOT')
report['baselineSnapshotFiles']=len(paths);report['baselineBinarySha256']=sha(work/'gitea.previous');report['baselineBundleSha256']=sha(work/'baseline.bundle');report['baselinePatchSha256']=sha(work/'baseline-working.patch')
emit('BASELINE_SAVED')
dbpath=work/'online-database-snapshot.sqlite'
original=sqlite3.connect('file:/home/git/gitea/data/gitea.db?mode=ro',uri=True,timeout=15)
original.execute('PRAGMA query_only=ON')
clone=sqlite3.connect(dbpath)
deadline=time.monotonic()+300
def progress(status,remaining,total):
if time.monotonic()>deadline:raise RuntimeError('DATABASE_SNAPSHOT_DEADLINE')
try:original.backup(clone,pages=1024,progress=progress,sleep=0.02)
finally:clone.close();original.close()
os.chmod(dbpath,0o600)
check=sqlite3.connect('file:'+str(dbpath)+'?mode=ro',uri=True)
integrity=[r[0] for r in check.execute('PRAGMA integrity_check')]
if integrity!=['ok']:raise RuntimeError('SNAPSHOT_INTEGRITY_FAILED')
report['databaseSnapshot']={'sha256':sha(dbpath),'bytes':dbpath.stat().st_size,'integrityCheck':'ok','schemaVersion':check.execute('SELECT version FROM version WHERE id=1').fetchone()[0],'scope':'SQLite online snapshot only; files not at same stop-write point'}
check.close();emit('ONLINE_DATABASE_SNAPSHOT_VERIFIED')
upstream=work/'candidate-source'
r=git(['clone','--depth','1','--branch','v1.27.3','--filter=blob:none','https://github.com/go-gitea/gitea.git',str(upstream)],cwd=work,timeout=600)
(work/'upstream-fetch.stdout').write_bytes(r.stdout);(work/'upstream-fetch.stderr').write_bytes(r.stderr)
if r.returncode:
report['status']='UPSTREAM_FETCH_FAILED';report['fetchExitCode']=r.returncode;emit('STOPPED_BEFORE_CANDIDATE_BUILD');raise SystemExit(0)
head=git(['rev-parse','HEAD'],cwd=upstream)
if head.returncode or head.stdout.decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('FIXED_UPSTREAM_COMMIT_MISMATCH')
report['upstream']={'tag':'v1.27.3','commit':head.stdout.decode().strip(),'purpose':'compatibility analysis candidate, not selected for deployment'}
changed=git(['diff','--name-only','--diff-filter=ACMRT','HEAD'])
if changed.returncode:raise RuntimeError('SOURCE_CHANGED_PATHS_UNAVAILABLE')
report['customizationMerge']=[]
merge=work/'merge-inputs';merge.mkdir(mode=0o700)
for i,name in enumerate(changed.stdout.decode().splitlines()):
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts:raise RuntimeError('UNSAFE_SOURCE_PATH')
# Existing migration edits are retained in the baseline; do not transplant the legacy migration list.
if name.startswith('models/migrations/'):
report['customizationMerge'].append({'path':name,'status':'HELD_FOR_EXPLICIT_MIGRATION_BRIDGE'});continue
target=upstream/name
if not target.is_file() or target.is_symlink():
report['customizationMerge'].append({'path':name,'status':'TARGET_PATH_CHANGED_REVIEW_REQUIRED'});continue
original_blob=git(['show','HEAD:'+name])
if original_blob.returncode:raise RuntimeError('BASE_BLOB_READ_FAILED')
theirs=(source/name).read_bytes().replace(b'code.gitea.io/gitea',b'gitea.dev')
ancestor=original_blob.stdout.replace(b'code.gitea.io/gitea',b'gitea.dev')
a=merge/(str(i)+'.ours');b=merge/(str(i)+'.base');c=merge/(str(i)+'.theirs')
a.write_bytes(target.read_bytes());b.write_bytes(ancestor);c.write_bytes(theirs)
m=git(['merge-file','-p',str(a),str(b),str(c)],cwd=work,timeout=30)
if m.returncode==0:
target.write_bytes(m.stdout);state='TEXTUAL_MERGE_CLEAN_SEMANTICS_UNVERIFIED'
elif 1<=m.returncode<=127:
(merge/(str(i)+'.conflicted')).write_bytes(m.stdout);state='SEMANTIC_REVIEW_REQUIRED'
else:state='MERGE_TOOL_FAILED'
report['customizationMerge'].append({'path':name,'status':state})
report['status']='PRIVATE_BASELINE_AND_SNAPSHOT_PREPARED'
report['candidateBuilt']=False;report['candidateMigrationExecuted']=False;report['sourceFingerprintAfter']=fingerprint(paths)
if report['sourceFingerprintAfter']!=before:raise RuntimeError('LIVE_SOURCE_CHANGED_DURING_PREPARATION')
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('PREPARED_FOR_REVIEW')
PY
shell: bash
timeout-minutes: "20"
permissions:
contents: read
...
|
prepare
|
null
|
["ubuntu-latest"]
|
37517
|
2
|
1793522195
|
1793522514
|
1793522183
|
1793522514
|
|
0
|
|
0
|
Edit
Delete
|
|
46056
|
26763
|
116
|
5
|
ab0f7a9662b7e37f9a553ef821c0cb2700017692
|
0
|
inspect
|
0
|
name: Gitea migration identity (read only)
"on name: Gitea migration identity (read only)
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-migration-identity.yml]
workflow_dispatch:
jobs:
inspect:
name: inspect
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Read migration mapping and schema column names
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, json, os, pathlib, re, socket, sqlite3, subprocess
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
source=pathlib.Path('/root/gitea-src')
env=dict(os.environ,GIT_OPTIONAL_LOCKS='0')
def git(*args):
r=subprocess.run(['git','--no-optional-locks','-C',str(source),*args],capture_output=True,text=True,timeout=30,env=env)
if r.returncode:raise RuntimeError('SOURCE_READ_FAILED')
return r.stdout
head=git('rev-parse','HEAD').strip()
if head!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('SOURCE_BASE_CHANGED')
report={'kind':'GiteaMigrationIdentityProbe','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':os.environ.get('GITHUB_RUN_ID')},'releaseEligible':False,'sourceHead':head,'serviceChanges':False,'databaseWrites':False}
path='models/migrations/migrations.go'
current=(source/path).read_text()
base=git('show','HEAD:'+path)
# This emits migration code only, from two fixed source paths; never configuration or row data.
def entries(text):
return [{'number':int(m.group(1)), 'description':m.group(2), 'function':m.group(3)} for m in re.finditer(r'newMigration\(\s*(\d+)\s*,\s*"([^"]+)"\s*,\s*([a-zA-Z0-9_.]+)',text)]
report['baseMigrationEntries']=entries(base)[-50:]
report['workingMigrationEntries']=entries(current)[-50:]
report['migrationFileSha256']=hashlib.sha256(current.encode()).hexdigest()
delta=git('diff','--no-ext-diff','--unified=3','HEAD','--',path,'models/migrations/v1_22/v299.go')
# Any unexpectedly embedded credential literal stops export, without printing it.
if re.search(r'(?:password|secret|token|private.?key)\s*[:=]\s*["\'][^"\']{8,}["\']',delta,re.I):raise RuntimeError('SENSITIVE_LITERAL_REFUSED')
report['migrationSourceDiff']=delta[:18000]
report['migrationSourceDiffTruncated']=len(delta)>18000
report['migrationSourceDiffSha256']=hashlib.sha256(delta.encode()).hexdigest()
report['goModuleHeader']=[x for x in (source/'go.mod').read_text().splitlines()[:6] if x.startswith(('module ','go ','toolchain '))]
connection=sqlite3.connect('file:/home/git/gitea/data/gitea.db?mode=ro',uri=True,timeout=15)
connection.execute('PRAGMA query_only=ON')
tables={row[0] for row in connection.execute("SELECT name FROM sqlite_master WHERE type='table'")}
selected=['version','action_run','action_run_job','action_run_attempt','action_artifact','protected_branch','repository','team','user']
report['schemaColumns']={t:[r[1] for r in connection.execute('PRAGMA table_info("'+t+'")')] if t in tables else None for t in selected}
report['schemaVersion']=connection.execute('SELECT version FROM version WHERE id=1').fetchone()[0]
connection.close()
print('GITEA_MIGRATION_IDENTITY_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
timeout-minutes: "5"
permissions:
contents: read
...
|
inspect
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793522621
|
1793522218
|
1793522621
|
|
1
|
|
0
|
Edit
Delete
|
|
46057
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Static checks (locked engineering dependency)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
public-static:
name: Static checks (locked engineering dependency)
runs-on: ubuntu-latest
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Test image release credential preflight (synthetic credentials only)
run: node --test .github/scripts/test/*.test.mjs
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Governance checks (exact engineering package; public contracts dependencies)
run: |
pnpm check:module-imports
pnpm check:canonical-ids
pnpm check:code-sets
pnpm check:omni-platform
pnpm check:fact-pii
pnpm check:catalog
pnpm check:migration-decs
pnpm check:caddy
pnpm test
pnpm contracts:check:local
- name: Pack publishable packages (contracts + governance; no publish)
run: |
rm -rf dist-artifacts
pnpm --dir contracts build
pnpm --dir governance pack --pack-destination ../dist-artifacts
pnpm --dir contracts pack --pack-destination ../dist-artifacts
ls -la dist-artifacts
- if: always()
name: Upload package tarballs
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-packages-${{ env.CANDIDATE_TAG }}
path: dist-artifacts/*.tgz
retention-days: "30"
- if: always()
name: Upload public static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-public-static-${{ env.CANDIDATE_TAG }}
path: reports/*.latest.json
retention-days: "30"
timeout-minutes: "15"
permissions:
contents: read
...
|
public-static
|
null
|
["ubuntu-latest"]
|
37518
|
2
|
1793522514
|
1793522605
|
1793522412
|
1793522605
|
|
0
|
|
0
|
Edit
Delete
|
|
46058
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Static governance (repo root, private packages)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
37519
|
2
|
1793522605
|
1793522902
|
1793522412
|
1793522902
|
|
0
|
|
0
|
Edit
Delete
|
|
46059
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate clients for authority module unit imports (no database)
run: pnpm --dir runtime prisma:generate
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
37522
|
4
|
1793522922
|
1793522922
|
1793522412
|
1793522923
|
|
1
|
|
0
|
Edit
Delete
|
|
46060
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Port conformance (kernel / modules / clients)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
37523
|
4
|
1793522924
|
1793522924
|
1793522412
|
1793522925
|
|
1
|
|
0
|
Edit
Delete
|
|
46061
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
# Compose parses all services even for --no-deps redpanda and down.
# These unused service values deliberately cannot start a runtime.
PLATFORM_DEPLOYMENT_ENV: test
PLATFORM_RUNTIME_IMAGE: enterprise-platform/runtime:ci-not-started
PLATFORM_RUNTIME_DATABASE_RUNTIME_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_DATABASE_SYSTEM_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_REDIS_URL: redis://127.0.0.1:1/15
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and provision every module acceptance database
run: |
pnpm runtime:build:modules
node governance/prepare-module-databases.mjs
- name: Prepare mainline fixtures and verify identity ordinary-role databases
run: |
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Build isolated MinIO from pinned upstream source
run: docker build -t enterprise-platform/test-minio:a6c538c5 stack/test-minio
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Registry admission and central audit recovery
run: pnpm check:registry-admission
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Configuration snapshots, tenant isolation and remote SDK acceptance
run: pnpm acceptance:configuration
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Identity signing against isolated OpenBao Transit
run: pnpm identity:check:transit
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload workbench browser diagnostics
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-workbench-browser-${{ env.CANDIDATE_TAG }}
path: /tmp/platform-workbench-ui-*/
retention-days: "7"
- if: always()
name: Upload runtime and UI evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/configuration-runtime.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
reports/registry-admission.latest.json
reports/identity-transit.latest.json
reports/scope-http.latest.json
reports/scope-fact-sla.latest.json
reports/machine-revocation-sla.latest.json
reports/credential-m1-sla.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
37524
|
4
|
1793522926
|
1793522926
|
1793522412
|
1793522927
|
|
1
|
|
0
|
Edit
Delete
|
|
46062
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; shared runtime identity fixture dependencies)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Build shared identity fixture dependencies from this checkout
run: |
pnpm --dir runtime install --frozen-lockfile --filter @juhai/module-identity... --filter @juhai/client-identity --filter api-nestjs
pnpm --dir runtime --filter @juhai/module-identity prisma:generate
pnpm --dir runtime exec turbo run build --filter=@juhai/module-identity... --filter=@juhai/client-identity...
pnpm --dir identity --filter api-nestjs exec node -e "require('node:assert/strict').strictEqual(require('@juhai/module-kit'), require('../../../runtime/modules/kit'))"
- name: Provision ordinary owner for the isolated identity test database
run: |
psql "${DATABASE_URL%%\?*}" -v ON_ERROR_STOP=1 <<'SQL'
CREATE ROLE enterprise_idp_ci_rt LOGIN PASSWORD 'ci-test-only' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;
ALTER DATABASE enterprise_idp_ci OWNER TO enterprise_idp_ci_rt;
ALTER SCHEMA public OWNER TO enterprise_idp_ci_rt;
SQL
echo 'DATABASE_URL=postgresql://enterprise_idp_ci_rt:ci-test-only@127.0.0.1:5432/enterprise_idp_ci?schema=public' >> "$GITHUB_ENV"
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (single NestJS host, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (single NestJS host)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
37525
|
4
|
1793522928
|
1793522928
|
1793522412
|
1793522929
|
|
1
|
|
0
|
Edit
Delete
|
|
46063
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: https://github.com/sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
37526
|
4
|
1793522930
|
1793522930
|
1793522412
|
1793522931
|
|
1
|
|
0
|
Edit
Delete
|
|
46064
|
26764
|
116
|
5
|
e58a53198e507f829b98893f5c73bfd896023b7a
|
0
|
Release candidate verification + manifest
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${GITHUB_RUN_ATTEMPT}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Download image and full SBOM evidence for the same candidate
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-image-${{ env.CANDIDATE_TAG }}
path: reports
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ needs.image.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity","image"]...
|
["ubuntu-latest"]
|
37527
|
2
|
1793522932
|
1793522944
|
1793522412
|
1793522944
|
|
1
|
|
0
|
Edit
Delete
|
|
46065
|
26765
|
116
|
5
|
61a8b9152ddd161ce816e35f6faa075933995d31
|
0
|
analyze
|
1
|
name: Gitea private compatibility analysis
"on name: Gitea private compatibility analysis
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-upgrade-analysis.yml]
workflow_dispatch:
jobs:
analyze:
name: analyze
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Verify saved baseline and analyze official fixed-source compatibility
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, json, os, pathlib, re, shutil, socket, sqlite3, subprocess, time
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
source=pathlib.Path('/root/gitea-src')
def sha(p):
h=hashlib.sha256()
with open(p,'rb') as f:
for b in iter(lambda:f.read(1024*1024),b''):h.update(b)
return h.hexdigest()
if sha('/usr/local/bin/gitea')!='640efd1256fe5ace902a1185bd6fdedd063ec1eec08422aceded8cc9559a8dc9':raise RuntimeError('INSTALLED_BINARY_CHANGED')
def source_files():
paths=[]
for root,dirs,files in os.walk(source):
dirs[:]=sorted(d for d in dirs if d not in ['.git','node_modules','.cache','.secrets','.evidence-private'])
for name in sorted(files):
if name.startswith('.env') or name.endswith(('.key','.pem')):continue
p=pathlib.Path(root)/name
if not p.is_symlink() and p.is_file():paths.append(p)
return paths
def fingerprint(paths):
h=hashlib.sha256()
for p in paths:h.update(str(p.relative_to(source)).encode()+b'\0'+bytes.fromhex(sha(p)))
return h.hexdigest()
paths=source_files();before=fingerprint(paths)
if before!='a5534f2aa03220a02efecac6753f0edcb99db7e8a3da323a1bac3390e2793d74':raise RuntimeError('REPRODUCED_SOURCE_CHANGED')
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
if shutil.disk_usage(base).free<40*1024**3:raise RuntimeError('STAGING_FREE_SPACE_REQUIRED')
work=base/('analysis-'+runid);work.mkdir(mode=0o700)
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
report={'kind':'GiteaUpgradeCompatibilityAnalysis','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'privateWorkspace':str(work),'liveServiceChanges':False,'liveDatabaseWrites':False,'fullConsistentBackup':False,'sourceFingerprint':before}
def emit(stage):
report['stage']=stage;print('GITEA_UPGRADE_ANALYSIS_JSON '+json.dumps(report,separators=(',',':')),flush=True)
def git(args,cwd=source,timeout=300):
return subprocess.run(['git','-c','credential.helper=','-c','core.askPass=','-c','http.extraHeader=','-c','core.hooksPath=/dev/null',*args],cwd=cwd,env=env,stdin=subprocess.DEVNULL,capture_output=True,timeout=timeout)
emit('PREPARING')
snapshot=base/'stage-26762'/'baseline-source'
h=hashlib.sha256()
for p in paths:
target=snapshot/p.relative_to(source)
if target.is_symlink() or not target.is_file():raise RuntimeError('BASELINE_SNAPSHOT_MISSING')
h.update(str(p.relative_to(source)).encode()+b'\0'+bytes.fromhex(sha(target)))
if h.hexdigest()!=before:raise RuntimeError('BASELINE_SNAPSHOT_FINGERPRINT_MISMATCH')
parent=base/'stage-26762'
if sha(parent/'gitea.previous')!='640efd1256fe5ace902a1185bd6fdedd063ec1eec08422aceded8cc9559a8dc9':raise RuntimeError('BASELINE_BINARY_MISMATCH')
verify=git(['bundle','verify',str(parent/'baseline.bundle')])
if verify.returncode:raise RuntimeError('BASELINE_BUNDLE_VERIFY_FAILED')
report['verifiedBaseline']={'path':str(parent),'sourceFingerprint':h.hexdigest(),'bundleSha256':sha(parent/'baseline.bundle'),'patchSha256':sha(parent/'baseline-working.patch'),'binarySha256':sha(parent/'gitea.previous')}
report['databaseSnapshot']='NOT_OBTAINED; prior online backup reached deadline; no retry in this job'
emit('BASELINE_FILES_AND_BUNDLE_VERIFIED')
upstream=work/'candidate-source'
r=git(['clone','--depth','1','--branch','v1.27.3','--filter=blob:none','https://github.com/go-gitea/gitea.git',str(upstream)],cwd=work,timeout=600)
(work/'upstream-fetch.stdout').write_bytes(r.stdout);(work/'upstream-fetch.stderr').write_bytes(r.stderr)
if r.returncode:
report['status']='UPSTREAM_FETCH_FAILED';report['fetchExitCode']=r.returncode;emit('STOPPED_BEFORE_CANDIDATE_BUILD');raise SystemExit(0)
head=git(['rev-parse','HEAD'],cwd=upstream)
if head.returncode or head.stdout.decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('FIXED_UPSTREAM_COMMIT_MISMATCH')
report['upstream']={'tag':'v1.27.3','commit':head.stdout.decode().strip(),'purpose':'compatibility analysis candidate, not selected for deployment'}
changed=git(['diff','--name-only','--diff-filter=ACMRT','HEAD'])
if changed.returncode:raise RuntimeError('SOURCE_CHANGED_PATHS_UNAVAILABLE')
report['customizationMerge']=[]
merge=work/'merge-inputs';merge.mkdir(mode=0o700)
for i,name in enumerate(changed.stdout.decode().splitlines()):
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts:raise RuntimeError('UNSAFE_SOURCE_PATH')
# Existing migration edits are retained in the baseline; do not transplant the legacy migration list.
if name.startswith('models/migrations/'):
report['customizationMerge'].append({'path':name,'status':'HELD_FOR_EXPLICIT_MIGRATION_BRIDGE'});continue
target=upstream/name
if not target.is_file() or target.is_symlink():
report['customizationMerge'].append({'path':name,'status':'TARGET_PATH_CHANGED_REVIEW_REQUIRED'});continue
original_blob=git(['show','HEAD:'+name])
if original_blob.returncode:raise RuntimeError('BASE_BLOB_READ_FAILED')
theirs=(source/name).read_bytes().replace(b'code.gitea.io/gitea',b'gitea.dev')
ancestor=original_blob.stdout.replace(b'code.gitea.io/gitea',b'gitea.dev')
a=merge/(str(i)+'.ours');b=merge/(str(i)+'.base');c=merge/(str(i)+'.theirs')
a.write_bytes(target.read_bytes());b.write_bytes(ancestor);c.write_bytes(theirs)
m=git(['merge-file','-p',str(a),str(b),str(c)],cwd=work,timeout=30)
if m.returncode==0:
target.write_bytes(m.stdout);state='TEXTUAL_MERGE_CLEAN_SEMANTICS_UNVERIFIED'
elif 1<=m.returncode<=127:
(merge/(str(i)+'.conflicted')).write_bytes(m.stdout);state='SEMANTIC_REVIEW_REQUIRED'
else:state='MERGE_TOOL_FAILED'
report['customizationMerge'].append({'path':name,'status':state})
untracked=git(['ls-files','--others','--exclude-standard'])
if untracked.returncode:raise RuntimeError('UNTRACKED_SOURCE_INVENTORY_FAILED')
report['untrackedCustomization']=[]
for name in untracked.stdout.decode().splitlines():
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts:raise RuntimeError('UNSAFE_UNTRACKED_PATH')
if not rel.parts or rel.parts[0] not in ['models','routers','services','modules','templates','options']:continue
if rel.suffix not in ['.go','.tmpl','.json']:continue
p=source/name;target=upstream/name
if p.is_symlink() or not p.is_file():continue
if target.exists():state='COLLISION_REVIEW_REQUIRED'
else:
target.parent.mkdir(parents=True,exist_ok=True)
target.write_bytes(p.read_bytes().replace(b'code.gitea.io/gitea',b'gitea.dev'))
state='PRESERVED_FROM_REPRODUCED_BASELINE_SEMANTICS_UNVERIFIED'
report['untrackedCustomization'].append({'path':name,'status':state})
report['status']='PRIVATE_BASELINE_VERIFIED_AND_COMPATIBILITY_ANALYZED'
report['candidateBuilt']=False;report['candidateMigrationExecuted']=False;report['sourceFingerprintAfter']=fingerprint(paths)
if report['sourceFingerprintAfter']!=before:raise RuntimeError('LIVE_SOURCE_CHANGED_DURING_PREPARATION')
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('PREPARED_FOR_REVIEW')
PY
shell: bash
timeout-minutes: "15"
permissions:
contents: read
...
|
analyze
|
null
|
["ubuntu-latest"]
|
37520
|
1
|
1793522902
|
1793522920
|
1793522621
|
1793522920
|
|
0
|
|
0
|
Edit
Delete
|
|
46066
|
26766
|
116
|
5
|
ca016ace1582ae89162d78541d6536840b0f2c97
|
0
|
inspect
|
1
|
name: Gitea migration identity (read only)
"on name: Gitea migration identity (read only)
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-migration-identity.yml]
workflow_dispatch:
jobs:
inspect:
name: inspect
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Read migration mapping and schema column names
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, json, os, pathlib, re, socket, sqlite3, subprocess
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
source=pathlib.Path('/root/gitea-src')
env=dict(os.environ,GIT_OPTIONAL_LOCKS='0')
def git(*args):
r=subprocess.run(['git','--no-optional-locks','-C',str(source),*args],capture_output=True,text=True,timeout=30,env=env)
if r.returncode:raise RuntimeError('SOURCE_READ_FAILED')
return r.stdout
head=git('rev-parse','HEAD').strip()
if head!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('SOURCE_BASE_CHANGED')
report={'kind':'GiteaMigrationIdentityProbe','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':os.environ.get('GITHUB_RUN_ID')},'releaseEligible':False,'sourceHead':head,'serviceChanges':False,'databaseWrites':False}
path='models/migrations/migrations.go'
current=(source/path).read_text()
base=git('show','HEAD:'+path)
# This emits migration code only, from two fixed source paths; never configuration or row data.
def entries(text):
return [{'number':int(m.group(1)), 'description':m.group(2), 'function':m.group(3)} for m in re.finditer(r'newMigration\(\s*(\d+)\s*,\s*"([^"]+)"\s*,\s*([a-zA-Z0-9_.]+)',text)]
report['baseMigrationEntries']=entries(base)[-50:]
report['workingMigrationEntries']=entries(current)[-50:]
report['migrationFileSha256']=hashlib.sha256(current.encode()).hexdigest()
delta=git('diff','--no-ext-diff','--unified=3','HEAD','--',path,'models/migrations/v1_22/v299.go')
# Any unexpectedly embedded credential literal stops export, without printing it.
if re.search(r'(?:password|secret|token|private.?key)\s*[:=]\s*["\'][^"\']{8,}["\']',delta,re.I):raise RuntimeError('SENSITIVE_LITERAL_REFUSED')
report['migrationSourceDiff']=delta[:18000]
report['migrationSourceDiffTruncated']=len(delta)>18000
report['migrationSourceDiffSha256']=hashlib.sha256(delta.encode()).hexdigest()
report['goModuleHeader']=[x for x in (source/'go.mod').read_text().splitlines()[:6] if x.startswith(('module ','go ','toolchain '))]
connection=sqlite3.connect('file:/home/git/gitea/data/gitea.db?mode=ro',uri=True,timeout=15)
connection.execute('PRAGMA query_only=ON')
tables={row[0] for row in connection.execute("SELECT name FROM sqlite_master WHERE type='table'")}
selected=['version','action_run','action_run_job','action_run_attempt','action_artifact','protected_branch','repository','team','user']
report['schemaColumns']={t:[r[1] for r in connection.execute('PRAGMA table_info("'+t+'")')] if t in tables else None for t in selected}
report['schemaVersion']=connection.execute('SELECT version FROM version WHERE id=1').fetchone()[0]
connection.close()
print('GITEA_MIGRATION_IDENTITY_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
timeout-minutes: "5"
permissions:
contents: read
...
|
inspect
|
null
|
["ubuntu-latest"]
|
37521
|
1
|
1793522920
|
1793522921
|
1793522697
|
1793522921
|
|
0
|
|
0
|
Edit
Delete
|
|
46067
|
26767
|
116
|
5
|
60974a766a52e7c45de627042ae4183c4462d2dc
|
0
|
inspect
|
1
|
name: Gitea maintenance capacity (read only)
" name: Gitea maintenance capacity (read only)
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-maintenance-capacity.yml]
workflow_dispatch:
jobs:
inspect:
name: inspect
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Read capacity, isolation capabilities and file mode metadata
run: |
set -eu
python3 <<'PY'
import datetime, json, os, pathlib, re, socket, stat
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
report={'kind':'GiteaMaintenanceCapacityProbe','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':os.environ.get('GITHUB_RUN_ID')},'releaseEligible':False,'writes':False}
report['cpuCount']=os.cpu_count()
report['memoryKiB']={k:int(v.split()[0]) for k,v in (line.split(':',1) for line in pathlib.Path('/proc/meminfo').read_text().splitlines()) if k in ['MemTotal','MemAvailable']}
cpu=pathlib.Path('/proc/cpuinfo').read_text()
report['hardwareVirtualizationFlagPresent']=any(x in cpu.split() for x in ['vmx','svm'])
report['devices']={p:{'exists':pathlib.Path(p).exists(),'readWrite':os.access(p,os.R_OK|os.W_OK),'characterDevice':stat.S_ISCHR(os.stat(p).st_mode) if pathlib.Path(p).exists() else False} for p in ['/dev/kvm','/dev/fuse']}
report['toolPresence']={p:pathlib.Path(p).is_file() for p in ['/usr/bin/qemu-system-x86_64','/usr/bin/dockerd-rootless.sh','/usr/bin/rootlesskit','/usr/bin/slirp4netns','/usr/bin/newuidmap','/usr/bin/fusermount3']}
report['mounts']=[]
for line in pathlib.Path('/proc/self/mountinfo').read_text().splitlines():
pre,post=line.split(' - ',1);fields=pre.split();fstype=post.split()[0];mount=fields[4]
if fstype not in ['ext4','xfs','btrfs','zfs','nfs','nfs4','fuse.sshfs'] or mount.startswith(('/var/lib/docker','/run/')):continue
try:
fs=os.statvfs(mount)
report['mounts'].append({'path':mount,'filesystem':fstype,'availableBytes':fs.f_bavail*fs.f_frsize,'totalBytes':fs.f_blocks*fs.f_frsize})
except OSError:pass
report['privatePathPermissions']=[]
for name in ['/home/git','/home/git/gitea','/home/git/gitea/config/app.ini','/home/git/repositories','/usr/local/bin/data','/opt/gitea-runner','/opt/gitea-runner/.runner']:
p=pathlib.Path(name)
if not p.exists():continue
s=p.stat();report['privatePathPermissions'].append({'path':name,'mode':oct(stat.S_IMODE(s.st_mode)),'uid':s.st_uid,'gid':s.st_gid})
selected={};parent=None
for line in pathlib.Path('/opt/gitea-runner/config.yaml').read_text().splitlines():
if not line.strip() or line.lstrip().startswith('#'):continue
if not line.startswith((' ','\t')):parent=line.split(':',1)[0].strip();continue
if ':' not in line:continue
key,value=line.strip().split(':',1)
if parent=='runner' and key=='labels':
value=value.strip()
selected['labelsConfiguredInYaml']=bool(value)
if parent=='container' and key in ['privileged','docker_host']:
value=value.strip().strip('"\'')
if value in ['true','false','-','']:selected[key]=value
else:selected[key]='CUSTOM_VALUE_NOT_EXPORTED'
report['runnerExecutorConfiguration']=selected
print('GITEA_MAINTENANCE_CAPACITY_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
timeout-minutes: "5"
permissions:
contents: read
...
|
inspect
|
null
|
["ubuntu-latest"]
|
37528
|
1
|
1793522985
|
1793522985
|
1793522983
|
1793522985
|
|
0
|
|
0
|
Edit
Delete
|
|
46068
|
26768
|
116
|
5
|
40769bdad3adf44ff656aa94a6c331826295a12b
|
0
|
repair
|
1
|
name: Repair runner registration file permissions
name: Repair runner registration file permissions
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-runner-permissions.yml]
workflow_dispatch:
jobs:
repair:
name: repair
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Limit existing root-owned registration to owner read-write
run: |
set -eu
python3 <<'PY'
import datetime, json, os, pathlib, socket, stat, subprocess
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_RECEIPT_BASE_REQUIRED')
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
stamp=datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%S%fZ')
target=base/('registration-permissions-'+runid+'-'+stamp+'.json')
def unit():
r=subprocess.run(['systemctl','show','gitea-runner.service','-p','User','-p','ActiveState','-p','MainPID'],capture_output=True,text=True,check=True,timeout=10)
return dict(row.split('=',1) for row in r.stdout.splitlines() if '=' in row)
before_unit=unit()
if before_unit.get('User') not in ['','root'] or before_unit.get('ActiveState')!='active' or not before_unit.get('MainPID','').isdigit():raise RuntimeError('ACTIVE_ROOT_RUNNER_REQUIRED')
path=pathlib.Path('/opt/gitea-runner/.runner')
parent=path.parent.lstat()
if not stat.S_ISDIR(parent.st_mode) or parent.st_uid!=0 or stat.S_IMODE(parent.st_mode)&0o022:raise RuntimeError('PROTECTED_REGISTRATION_DIRECTORY_REQUIRED')
fd=os.open(path,os.O_RDONLY|os.O_NOFOLLOW)
try:
before=os.fstat(fd)
if not stat.S_ISREG(before.st_mode) or before.st_uid!=0 or before.st_gid!=0 or before.st_nlink!=1:raise RuntimeError('EXPECTED_ROOT_REGISTRATION_FILE_REQUIRED')
mode=stat.S_IMODE(before.st_mode)
if mode not in [0o644,0o600]:raise RuntimeError('UNEXPECTED_REGISTRATION_PERMISSIONS')
if mode!=0o600:os.fchmod(fd,0o600)
after=os.fstat(fd);current=path.lstat()
if (after.st_dev,after.st_ino)!=(current.st_dev,current.st_ino):raise RuntimeError('REGISTRATION_PATH_CHANGED')
if (after.st_dev,after.st_ino,after.st_size,after.st_mtime_ns)!=(before.st_dev,before.st_ino,before.st_size,before.st_mtime_ns):raise RuntimeError('REGISTRATION_CONTENT_METADATA_CHANGED')
if stat.S_IMODE(after.st_mode)!=0o600:raise RuntimeError('PERMISSION_REPAIR_FAILED')
finally:os.close(fd)
after_unit=unit()
if after_unit!=before_unit:raise RuntimeError('RUNNER_SERVICE_STATE_CHANGED')
report={'kind':'GiteaRunnerRegistrationPermissionRepair','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':os.environ.get('GITHUB_RUN_ID')},'releaseEligible':False,'path':str(path),'beforeMode':oct(mode),'afterMode':'0o600','ownerUid':0,'ownerGid':0,'changed':mode!=0o600,'contentRead':False,'contentWritten':False,'contentMetadataUnchanged':True,'runnerServiceBefore':before_unit,'runnerServiceAfter':after_unit,'serviceRestarted':False,'giteaBinaryOrDatabaseChanged':False,'fullExecutorIsolationAccepted':False}
with open(target,'x') as f:json.dump(report,f,indent=2);f.write('\n')
print('GITEA_RUNNER_PERMISSION_REPAIR_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
timeout-minutes: "5"
permissions:
contents: read
...
|
repair
|
null
|
["ubuntu-latest"]
|
37529
|
1
|
1793523139
|
1793523139
|
1793523138
|
1793523139
|
|
0
|
|
0
|
Edit
Delete
|
|
46069
|
26769
|
116
|
5
|
69eaa5a92e2dd482077892245a13f268cb11b353
|
0
|
export
|
1
|
name: Export screened Gitea customization for revi name: Export screened Gitea customization for review
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-source-review-export.yml]
workflow_dispatch:
jobs:
export:
name: export
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Screen only known source changes and produce a review archive
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, io, json, os, pathlib, re, socket, subprocess, tarfile
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
analysis=base/'analysis-26765'
receipt=json.loads((analysis/'receipt.json').read_text())
if receipt.get('status')!='PRIVATE_BASELINE_VERIFIED_AND_COMPATIBILITY_ANALYZED':raise RuntimeError('VERIFIED_BASELINE_REQUIRED')
source=base/'stage-26762'/'baseline-source'
live=pathlib.Path('/root/gitea-src')
upstream=analysis/'candidate-source'
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(base),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_OPTIONAL_LOCKS':'0','GIT_TERMINAL_PROMPT':'0'}
def git(path,*args):
r=subprocess.run(['git','--no-optional-locks','-c','core.hooksPath=/dev/null','-C',str(path),*args],capture_output=True,timeout=30,env=env)
return r.returncode,r.stdout
code,head=git(upstream,'rev-parse','HEAD')
if code or head.decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('FIXED_OFFICIAL_SOURCE_REQUIRED')
paths=sorted({r['path'] for r in receipt['customizationMerge']+receipt['untrackedCustomization']})
def public_literals(text):
return set(re.findall(r'["\']([^"\'\n]{8,})["\']',text))
def suspicious(text,public,is_git_test=False):
issues=[]
if re.search(r'-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|(?:ghp_|github_pat_|AKIA[0-9A-Z]{16}|sk-(?:proj-)?)[A-Za-z0-9_/-]{12,}',text):issues.append('credential-prefix-or-private-key')
if re.search(r'https?://[^/\s:@]+:[^/\s@]+@',text):issues.append('credential-in-url')
for match in re.finditer(r'(?i)(?:[A-Za-z0-9_]*(?:password|passwd|secret|token|api_?key|access_?key|private_?key)[A-Za-z0-9_]*)\s*(?::=|=|:)\s*["\']([^"\'\n]{8,})["\']',text):
value=match.group(1)
if value not in public:issues.append('nonpublic-credential-literal')
for match in re.finditer(r'(?i)(?:Bearer|Basic)\s+[A-Za-z0-9_+/=.-]{12,}',text):
if not any(match.group(0) in literal for literal in public):issues.append('nonpublic-authorization-literal')
for value in re.findall(r'["\']([A-Za-z0-9+/=_-]{32,})["\']',text):
if value not in public and len(set(value))>8 and not is_git_test:issues.append('nonpublic-long-opaque-literal')
if not is_git_test:
for value in re.findall(r'["\']([A-Fa-f0-9]{32,128})["\']',text):
if value not in public and len(set(value))>3:issues.append('nonpublic-long-hex-literal')
return sorted(set(issues))
payload={};manifest=[];refused=[]
for name in paths:
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts or not rel.parts or rel.parts[0] not in ['models','routers','services','modules','templates','options'] or rel.suffix not in ['.go','.tmpl','.json']:raise RuntimeError('SOURCE_EXPORT_PATH_REFUSED')
p=source/name
if p.is_symlink() or not p.is_file():raise RuntimeError('SOURCE_EXPORT_NONREGULAR_FILE')
data=p.read_bytes()
if len(data)>2*1024*1024:raise RuntimeError('SOURCE_FILE_SIZE_LIMIT')
rc,public=git(upstream,'show','HEAD:'+name)
known=public_literals(public.decode(errors='replace')) if rc==0 else set()
candidates=[('current/'+name,data)]
rc,old=git(live,'show','HEAD:'+name)
if rc==0:candidates.append(('base/'+name,old))
for archive_name,body in candidates:
problems=suspicious(body.decode('utf-8'),known,name.startswith('modules/git/') and name.endswith('_test.go'))
if problems:refused.append({'path':archive_name,'reasons':problems});continue
payload[archive_name]=body
manifest.append({'path':archive_name,'bytes':len(body),'sha256':hashlib.sha256(body).hexdigest()})
report={'kind':'GiteaCustomSourceReviewExport','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceBaselineFingerprint':receipt['sourceFingerprint'],'upstreamCommit':head.decode().strip(),'serviceChanges':False,'databaseOrConfigurationExported':False,'registrationOrCredentialFilesRead':False,'refusedFiles':refused}
if refused:
report['status']='BLOCKED_CREDENTIAL_SCREENING';print('GITEA_CUSTOM_SOURCE_EXPORT_JSON '+json.dumps(report,separators=(',',':')));raise SystemExit(1)
if sum(len(v) for v in payload.values())>8*1024*1024:raise RuntimeError('SOURCE_EXPORT_SIZE_LIMIT')
work=base/('export-'+runid);work.mkdir(mode=0o700)
index={'kind':'GiteaCustomSourceReviewManifest','sourceBaselineFingerprint':receipt['sourceFingerprint'],'originalSourceHead':'287bf811487c04cd90bcf07aa04905cbaf2e4c2d','upstreamCommit':head.decode().strip(),'files':manifest,'scope':'Selected code only, not a system backup; no database, config, registration, environment, key or dependency cache files'}
payload['manifest.json']=(json.dumps(index,ensure_ascii=False,indent=2)+'\n').encode()
target=work/'gitea-custom-source.tar.gz'
with tarfile.open(target,'w:gz') as archive:
for name,body in sorted(payload.items()):
entry=tarfile.TarInfo(name);entry.size=len(body);entry.mode=0o600;entry.mtime=0;archive.addfile(entry,io.BytesIO(body))
report.update({'status':'SOURCE_CODE_SCREENED_AND_PACKED','fileCount':len(manifest),'archiveBytes':target.stat().st_size,'archiveSha256':hashlib.sha256(target.read_bytes()).hexdigest(),'privateArchive':str(target)})
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
print('GITEA_CUSTOM_SOURCE_EXPORT_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
- name: Upload screened source code for the authorized maintenance review
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: gitea-custom-source-${{ github.sha }}-${{ github.run_id }}
path: /var/lib/eios-r1-maintenance/export-${{ github.run_id }}/gitea-custom-source.tar.gz
retention-days: "1"
timeout-minutes: "15"
permissions:
contents: read
...
|
export
|
null
|
["ubuntu-latest"]
|
37530
|
2
|
1793523284
|
1793523286
|
1793523283
|
1793523287
|
|
0
|
|
0
|
Edit
Delete
|
|
46070
|
26770
|
116
|
5
|
a38a9a4392729248fe3ac45957c7c428f78510f4
|
0
|
export
|
1
|
name: Export screened Gitea customization for revi name: Export screened Gitea customization for review
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-source-review-export.yml]
workflow_dispatch:
jobs:
export:
name: export
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Screen only known source changes and produce a review archive
run: |
set -eu
python3 <<'PY'
import base64, datetime, hashlib, io, json, os, pathlib, re, socket, subprocess, tarfile
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
analysis=base/'analysis-26765'
receipt=json.loads((analysis/'receipt.json').read_text())
if receipt.get('status')!='PRIVATE_BASELINE_VERIFIED_AND_COMPATIBILITY_ANALYZED':raise RuntimeError('VERIFIED_BASELINE_REQUIRED')
source=base/'stage-26762'/'baseline-source'
live=pathlib.Path('/root/gitea-src')
upstream=analysis/'candidate-source'
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(base),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_OPTIONAL_LOCKS':'0','GIT_TERMINAL_PROMPT':'0'}
def git(path,*args):
r=subprocess.run(['git','--no-optional-locks','-c','core.hooksPath=/dev/null','-C',str(path),*args],capture_output=True,timeout=30,env=env)
return r.returncode,r.stdout
code,head=git(upstream,'rev-parse','HEAD')
if code or head.decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('FIXED_OFFICIAL_SOURCE_REQUIRED')
paths=sorted({r['path'] for r in receipt['customizationMerge']+receipt['untrackedCustomization']})
def public_literals(text):
return set(re.findall(r'["\']([^"\'\n]{8,})["\']',text))
def suspicious(text,public,is_git_test=False):
issues=[]
if re.search(r'-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|(?:ghp_|github_pat_|AKIA[0-9A-Z]{16}|sk-(?:proj-)?)[A-Za-z0-9_/-]{12,}',text):issues.append('credential-prefix-or-private-key')
if re.search(r'https?://[^/\s:@]+:[^/\s@]+@',text):issues.append('credential-in-url')
for match in re.finditer(r'(?i)(?:[A-Za-z0-9_]*(?:password|passwd|secret|token|api_?key|access_?key|private_?key)[A-Za-z0-9_]*)\s*(?::=|=|:)\s*["\']([^"\'\n]{8,})["\']',text):
value=match.group(1)
if value not in public:issues.append('nonpublic-credential-literal')
for match in re.finditer(r'(?i)(?:Bearer|Basic)\s+[A-Za-z0-9_+/=.-]{12,}',text):
if not any(match.group(0) in literal for literal in public):issues.append('nonpublic-authorization-literal')
for value in re.findall(r'["\']([A-Za-z0-9+/=_-]{32,})["\']',text):
if value not in public and len(set(value))>8 and not is_git_test:issues.append('nonpublic-long-opaque-literal')
if not is_git_test:
for value in re.findall(r'["\']([A-Fa-f0-9]{32,128})["\']',text):
if value not in public and len(set(value))>3:issues.append('nonpublic-long-hex-literal')
return sorted(set(issues))
payload={};manifest=[];refused=[]
for name in paths:
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts or not rel.parts or rel.parts[0] not in ['models','routers','services','modules','templates','options'] or rel.suffix not in ['.go','.tmpl','.json']:raise RuntimeError('SOURCE_EXPORT_PATH_REFUSED')
p=source/name
if p.is_symlink() or not p.is_file():raise RuntimeError('SOURCE_EXPORT_NONREGULAR_FILE')
data=p.read_bytes()
if len(data)>2*1024*1024:raise RuntimeError('SOURCE_FILE_SIZE_LIMIT')
rc,public=git(upstream,'show','HEAD:'+name)
known=public_literals(public.decode(errors='replace')) if rc==0 else set()
candidates=[('current/'+name,data)]
rc,old=git(live,'show','HEAD:'+name)
if rc==0:candidates.append(('base/'+name,old))
for archive_name,body in candidates:
problems=suspicious(body.decode('utf-8'),known,name.startswith('modules/git/') and name.endswith('_test.go'))
if problems:
text=body.decode('utf-8');classification=[]
for m in re.finditer(r'-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|(?:ghp_|github_pat_|AKIA[0-9A-Z]{16}|sk-(?:proj-)?)[A-Za-z0-9_/-]{12,}',text):
classification.append({'category':'prefix','publicSshAlgorithm':bool(re.match(r'sk-(?:ecdsa-sha2-nistp256|ssh-ed25519)@openssh\.com',text[m.start():])),'presentInOfficialLiteral':any(m.group(0) in v for v in known)})
for m in re.finditer(r'(?i)(Bearer|Basic)\s+([A-Za-z0-9_+/=.-]{12,})',text):
line=text[text.rfind('\n',0,m.start())+1:m.start()]
valid=False
if m.group(1).lower()=='basic':
try:
decoded=base64.b64decode(m.group(2)+'='*((-len(m.group(2)))%4),validate=True).decode('utf-8')
valid=':' in decoded and decoded.isprintable()
except Exception:pass
classification.append({'category':'authorization','scheme':m.group(1).lower(),'commentLine':line.lstrip().startswith('//'),'validPrintableBasicCredential':valid,'presentInOfficialLiteral':any(m.group(0) in v for v in known)})
for value in re.findall(r'["\']([A-Za-z0-9+/=_-]{32,})["\']',text):
if value not in known and len(set(value))>8 and not (name.startswith('modules/git/') and name.endswith('_test.go')):
classification.append({'category':'opaque','publicGitSmartHttpMime':value in ['application/x-git-upload-pack-advertisement','application/x-git-receive-pack-advertisement','application/x-git-upload-pack-result','application/x-git-receive-pack-result']})
refused.append({'path':archive_name,'reasons':problems,'classification':classification});continue
payload[archive_name]=body
manifest.append({'path':archive_name,'bytes':len(body),'sha256':hashlib.sha256(body).hexdigest()})
report={'kind':'GiteaCustomSourceReviewExport','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceBaselineFingerprint':receipt['sourceFingerprint'],'upstreamCommit':head.decode().strip(),'serviceChanges':False,'databaseOrConfigurationExported':False,'registrationOrCredentialFilesRead':False,'refusedFiles':refused}
if refused:
report['status']='BLOCKED_CREDENTIAL_SCREENING';print('GITEA_CUSTOM_SOURCE_EXPORT_JSON '+json.dumps(report,separators=(',',':')));raise SystemExit(1)
if sum(len(v) for v in payload.values())>8*1024*1024:raise RuntimeError('SOURCE_EXPORT_SIZE_LIMIT')
work=base/('export-'+runid);work.mkdir(mode=0o700)
index={'kind':'GiteaCustomSourceReviewManifest','sourceBaselineFingerprint':receipt['sourceFingerprint'],'originalSourceHead':'287bf811487c04cd90bcf07aa04905cbaf2e4c2d','upstreamCommit':head.decode().strip(),'files':manifest,'scope':'Selected code only, not a system backup; no database, config, registration, environment, key or dependency cache files'}
payload['manifest.json']=(json.dumps(index,ensure_ascii=False,indent=2)+'\n').encode()
target=work/'gitea-custom-source.tar.gz'
with tarfile.open(target,'w:gz') as archive:
for name,body in sorted(payload.items()):
entry=tarfile.TarInfo(name);entry.size=len(body);entry.mode=0o600;entry.mtime=0;archive.addfile(entry,io.BytesIO(body))
report.update({'status':'SOURCE_CODE_SCREENED_AND_PACKED','fileCount':len(manifest),'archiveBytes':target.stat().st_size,'archiveSha256':hashlib.sha256(target.read_bytes()).hexdigest(),'privateArchive':str(target)})
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
print('GITEA_CUSTOM_SOURCE_EXPORT_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
- name: Upload screened source code for the authorized maintenance review
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: gitea-custom-source-${{ github.sha }}-${{ github.run_id }}
path: /var/lib/eios-r1-maintenance/export-${{ github.run_id }}/gitea-custom-source.tar.gz
retention-days: "1"
timeout-minutes: "15"
permissions:
contents: read
...
|
export
|
null
|
["ubuntu-latest"]
|
37531
|
2
|
1793523423
|
1793523426
|
1793523422
|
1793523426
|
|
0
|
|
0
|
Edit
Delete
|
|
46071
|
26771
|
116
|
5
|
fc9741d6f8dca2a2f251ac2e1b15b724030e7a02
|
0
|
export
|
1
|
name: Export screened Gitea customization for revi name: Export screened Gitea customization for review
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-source-review-export.yml]
workflow_dispatch:
jobs:
export:
name: export
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Screen only known source changes and produce a review archive
run: |
set -eu
python3 <<'PY'
import base64, datetime, hashlib, io, json, os, pathlib, re, socket, subprocess, tarfile
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
analysis=base/'analysis-26765'
receipt=json.loads((analysis/'receipt.json').read_text())
if receipt.get('status')!='PRIVATE_BASELINE_VERIFIED_AND_COMPATIBILITY_ANALYZED':raise RuntimeError('VERIFIED_BASELINE_REQUIRED')
source=base/'stage-26762'/'baseline-source'
live=pathlib.Path('/root/gitea-src')
upstream=analysis/'candidate-source'
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(base),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_OPTIONAL_LOCKS':'0','GIT_TERMINAL_PROMPT':'0'}
def git(path,*args):
r=subprocess.run(['git','--no-optional-locks','-c','core.hooksPath=/dev/null','-C',str(path),*args],capture_output=True,timeout=30,env=env)
return r.returncode,r.stdout
code,head=git(upstream,'rev-parse','HEAD')
if code or head.decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('FIXED_OFFICIAL_SOURCE_REQUIRED')
# Export only files that require manual conflict or migration review.
# Already textually merged files and additive files stay on the server for native testing.
paths=sorted({r['path'] for r in receipt['customizationMerge'] if r['status'] in ['SEMANTIC_REVIEW_REQUIRED','HELD_FOR_EXPLICIT_MIGRATION_BRIDGE']})
def public_literals(text):
return set(re.findall(r'["\']([^"\'\n]{8,})["\']',text))
def suspicious(text,public,is_git_test=False):
issues=[]
for m in re.finditer(r'-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|(?:ghp_|github_pat_|AKIA[0-9A-Z]{16}|sk-(?:proj-)?)[A-Za-z0-9_/-]{12,}',text):
public_ssh=bool(re.match(r'sk-(?:ecdsa-sha2-nistp256|ssh-ed25519)@openssh\.com',text[m.start():])) and any(m.group(0) in v for v in public)
if not public_ssh:issues.append('credential-prefix-or-private-key')
if re.search(r'https?://[^/\s:@]+:[^/\s@]+@',text):issues.append('credential-in-url')
for match in re.finditer(r'(?i)(?:[A-Za-z0-9_]*(?:password|passwd|secret|token|api_?key|access_?key|private_?key)[A-Za-z0-9_]*)\s*(?::=|=|:)\s*["\']([^"\'\n]{8,})["\']',text):
value=match.group(1)
if value not in public:issues.append('nonpublic-credential-literal')
for match in re.finditer(r'(?i)(?:Bearer|Basic)\s+[A-Za-z0-9_+/=.-]{12,}',text):
if not any(match.group(0) in literal for literal in public):issues.append('nonpublic-authorization-literal')
for value in re.findall(r'["\']([A-Za-z0-9+/=_-]{32,})["\']',text):
if value not in public and len(set(value))>8 and not is_git_test:issues.append('nonpublic-long-opaque-literal')
if not is_git_test:
for value in re.findall(r'["\']([A-Fa-f0-9]{32,128})["\']',text):
if value not in public and len(set(value))>3:issues.append('nonpublic-long-hex-literal')
return sorted(set(issues))
payload={};manifest=[];refused=[]
for name in paths:
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts or not rel.parts or rel.parts[0] not in ['models','routers','services','modules','templates','options'] or rel.suffix not in ['.go','.tmpl','.json']:raise RuntimeError('SOURCE_EXPORT_PATH_REFUSED')
p=source/name
if p.is_symlink() or not p.is_file():raise RuntimeError('SOURCE_EXPORT_NONREGULAR_FILE')
data=p.read_bytes()
if len(data)>2*1024*1024:raise RuntimeError('SOURCE_FILE_SIZE_LIMIT')
rc,public=git(upstream,'show','HEAD:'+name)
known=public_literals(public.decode(errors='replace')) if rc==0 else set()
candidates=[('current/'+name,data)]
rc,old=git(live,'show','HEAD:'+name)
if rc==0:candidates.append(('base/'+name,old))
for archive_name,body in candidates:
problems=suspicious(body.decode('utf-8'),known,name.startswith('modules/git/') and name.endswith('_test.go'))
if problems:
text=body.decode('utf-8');classification=[]
for m in re.finditer(r'-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|(?:ghp_|github_pat_|AKIA[0-9A-Z]{16}|sk-(?:proj-)?)[A-Za-z0-9_/-]{12,}',text):
classification.append({'category':'prefix','publicSshAlgorithm':bool(re.match(r'sk-(?:ecdsa-sha2-nistp256|ssh-ed25519)@openssh\.com',text[m.start():])),'presentInOfficialLiteral':any(m.group(0) in v for v in known)})
for m in re.finditer(r'(?i)(Bearer|Basic)\s+([A-Za-z0-9_+/=.-]{12,})',text):
line=text[text.rfind('\n',0,m.start())+1:m.start()]
valid=False
if m.group(1).lower()=='basic':
try:
decoded=base64.b64decode(m.group(2)+'='*((-len(m.group(2)))%4),validate=True).decode('utf-8')
valid=':' in decoded and decoded.isprintable()
except Exception:pass
classification.append({'category':'authorization','scheme':m.group(1).lower(),'commentLine':line.lstrip().startswith('//'),'validPrintableBasicCredential':valid,'presentInOfficialLiteral':any(m.group(0) in v for v in known)})
for value in re.findall(r'["\']([A-Za-z0-9+/=_-]{32,})["\']',text):
if value not in known and len(set(value))>8 and not (name.startswith('modules/git/') and name.endswith('_test.go')):
classification.append({'category':'opaque','publicGitSmartHttpMime':value in ['application/x-git-upload-pack-advertisement','application/x-git-receive-pack-advertisement','application/x-git-upload-pack-result','application/x-git-receive-pack-result']})
refused.append({'path':archive_name,'reasons':problems,'classification':classification});continue
payload[archive_name]=body
manifest.append({'path':archive_name,'bytes':len(body),'sha256':hashlib.sha256(body).hexdigest()})
report={'kind':'GiteaCustomSourceReviewExport','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceBaselineFingerprint':receipt['sourceFingerprint'],'upstreamCommit':head.decode().strip(),'serviceChanges':False,'databaseOrConfigurationExported':False,'registrationOrCredentialFilesRead':False,'refusedFiles':refused}
if refused:
report['status']='BLOCKED_CREDENTIAL_SCREENING';print('GITEA_CUSTOM_SOURCE_EXPORT_JSON '+json.dumps(report,separators=(',',':')));raise SystemExit(1)
if sum(len(v) for v in payload.values())>8*1024*1024:raise RuntimeError('SOURCE_EXPORT_SIZE_LIMIT')
work=base/('export-'+runid);work.mkdir(mode=0o700)
index={'kind':'GiteaCustomSourceReviewManifest','sourceBaselineFingerprint':receipt['sourceFingerprint'],'originalSourceHead':'287bf811487c04cd90bcf07aa04905cbaf2e4c2d','upstreamCommit':head.decode().strip(),'files':manifest,'scope':'Selected code only, not a system backup; no database, config, registration, environment, key or dependency cache files'}
payload['manifest.json']=(json.dumps(index,ensure_ascii=False,indent=2)+'\n').encode()
target=work/'gitea-custom-source.tar.gz'
with tarfile.open(target,'w:gz') as archive:
for name,body in sorted(payload.items()):
entry=tarfile.TarInfo(name);entry.size=len(body);entry.mode=0o600;entry.mtime=0;archive.addfile(entry,io.BytesIO(body))
report.update({'status':'SOURCE_CODE_SCREENED_AND_PACKED','fileCount':len(manifest),'archiveBytes':target.stat().st_size,'archiveSha256':hashlib.sha256(target.read_bytes()).hexdigest(),'privateArchive':str(target)})
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
print('GITEA_CUSTOM_SOURCE_EXPORT_JSON '+json.dumps(report,separators=(',',':')))
PY
shell: bash
- name: Upload screened source code for the authorized maintenance review
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: gitea-custom-source-${{ github.sha }}-${{ github.run_id }}
path: /var/lib/eios-r1-maintenance/export-${{ github.run_id }}/gitea-custom-source.tar.gz
retention-days: "1"
timeout-minutes: "15"
permissions:
contents: read
...
|
export
|
null
|
["ubuntu-latest"]
|
37532
|
1
|
1793523526
|
1793523529
|
1793523526
|
1793523529
|
|
0
|
|
0
|
Edit
Delete
|
|
46072
|
26772
|
116
|
5
|
0d9c557d7e288e62a71638faab3a8507eac1cd7b
|
0
|
inspect
|
1
|
name: Verify full Gitea customization ancestry
name: Verify full Gitea customization ancestry
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-customization-ancestry.yml]
workflow_dispatch:
jobs:
inspect:
name: inspect
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Locate official common ancestor without writing live source refs
run: |
set -eu
python3 <<'PY'
import datetime, json, os, pathlib, socket, subprocess
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
work=base/('ancestry-'+runid);work.mkdir(mode=0o700)
source=pathlib.Path('/root/gitea-src');candidate=base/'analysis-26765'/'candidate-source'
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
def git(where,*args,timeout=30):
return subprocess.run(['git','-c','credential.helper=','-c','core.askPass=','-c','http.extraHeader=','-c','core.hooksPath=/dev/null','-C',str(where),*args],env=env,capture_output=True,timeout=timeout)
r=git(source,'rev-parse','HEAD')
if r.returncode or r.stdout.decode().strip()!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('SOURCE_HEAD_CHANGED')
r=git(candidate,'rev-parse','HEAD')
if r.returncode or r.stdout.decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('UPSTREAM_HEAD_CHANGED')
report={'kind':'GiteaCustomizationAncestryProbe','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'liveSourceOrServiceChanged':False,'privateGitHistoryFetchOnly':True}
r=git(source,'log','--first-parent','-12','--format=%H %P %cI')
report['sourceFirstParentMetadata']=r.stdout.decode().splitlines() if r.returncode==0 else []
report['sourceShallow']=git(source,'rev-parse','--is-shallow-repository').stdout.decode().strip()
def emit(stage):
report['stage']=stage;print('GITEA_CUSTOM_ANCESTRY_JSON '+json.dumps(report,separators=(',',':')),flush=True)
emit('FETCHING_OFFICIAL_HISTORY_PRIVATELY')
shallow=git(candidate,'rev-parse','--is-shallow-repository').stdout.decode().strip()
args=['fetch','--no-tags','--filter=blob:none']
if shallow=='true':args.append('--unshallow')
args+=['https://github.com/go-gitea/gitea.git','refs/tags/v1.27.3']
r=git(candidate,*args,timeout=600)
(work/'official-fetch.stdout').write_bytes(r.stdout);(work/'official-fetch.stderr').write_bytes(r.stderr)
if r.returncode:
report['status']='OFFICIAL_HISTORY_FETCH_FAILED';report['exitCode']=r.returncode;emit('STOPPED');raise SystemExit(0)
r=git(candidate,'fetch','--no-tags',str(source),'HEAD:refs/heads/maintenance-current-custom-base',timeout=300)
(work/'custom-fetch.stdout').write_bytes(r.stdout);(work/'custom-fetch.stderr').write_bytes(r.stderr)
if r.returncode:
report['status']='CUSTOM_HISTORY_FETCH_FAILED';report['exitCode']=r.returncode;emit('STOPPED');raise SystemExit(0)
r=git(candidate,'merge-base','--all','146cc3eec57174711eac0e0a0c7b38670c6e3922','287bf811487c04cd90bcf07aa04905cbaf2e4c2d')
commons=r.stdout.decode().splitlines() if r.returncode==0 else []
report['commonAncestors']=commons
if len(commons)!=1:
report['status']='NO_UNIQUE_VERIFIABLE_COMMON_ANCESTOR';emit('STOPPED');raise SystemExit(0)
common=commons[0]
r=git(candidate,'show','-s','--format=%H %cI',common)
report['commonAncestorMetadata']=r.stdout.decode().strip() if r.returncode==0 else None
r=git(candidate,'diff','--no-ext-diff','--no-textconv','--numstat',common,'287bf811487c04cd90bcf07aa04905cbaf2e4c2d',timeout=120)
if r.returncode:raise RuntimeError('COMMITTED_FORK_DIFF_FAILED')
rows=[]
for line in r.stdout.decode().splitlines():
fields=line.split('\t',2)
if len(fields)!=3:continue
name=fields[2]
if any(x in name.lower() for x in ['.env','secret','credential','password','.pem','.key']):name='SENSITIVE_PATH_NOT_EXPORTED'
rows.append({'added':fields[0],'removed':fields[1],'path':name})
report['committedForkChangedFileCount']=len(rows)
report['committedForkDelta']=rows[:120]
report['committedForkDeltaTruncated']=len(rows)>120
report['status']='COMMON_ANCESTOR_AND_COMMITTED_CUSTOMIZATION_IDENTIFIED'
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('COMPLETE')
PY
shell: bash
timeout-minutes: "20"
permissions:
contents: read
...
|
inspect
|
null
|
["ubuntu-latest"]
|
37533
|
1
|
1793523921
|
1793523932
|
1793523920
|
1793523932
|
|
0
|
|
0
|
Edit
Delete
|
|
46073
|
26773
|
116
|
5
|
76238b5a54238e0e6f5486504b85c4fddc0b0a0e
|
0
|
inspect
|
1
|
name: Locate official Gitea reference by file fing name: Locate official Gitea reference by file fingerprints
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-reference-fingerprint.yml]
workflow_dispatch:
jobs:
inspect:
name: inspect
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Compare public source fingerprints without claiming Git ancestry
run: |
set -eu
python3 <<'PY'
import datetime, json, os, pathlib, re, socket, subprocess, time
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
work=base/('fingerprint-'+runid);work.mkdir(mode=0o700)
source=pathlib.Path('/root/gitea-src');official=base/'analysis-26765'/'candidate-source'
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
def git(where,*args,timeout=30):
r=subprocess.run(['git','--no-optional-locks','-c','core.hooksPath=/dev/null','-C',str(where),*args],env=env,capture_output=True,timeout=timeout)
if r.returncode:raise RuntimeError('GIT_METADATA_QUERY_FAILED')
return r.stdout
head=git(source,'rev-parse','HEAD').decode().strip()
if head!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('SOURCE_HEAD_CHANGED')
if git(official,'rev-parse','HEAD').decode().strip()!='146cc3eec57174711eac0e0a0c7b38670c6e3922':raise RuntimeError('OFFICIAL_HEAD_CHANGED')
def tree(repo,commit):
result={}
for row in git(repo,'ls-tree','-r','-z','--format=%(objecttype) %(objectname) %(path)',commit,timeout=30).split(b'\0'):
if not row:continue
kind,oid,name=row.split(b' ',2)
if kind==b'blob':result[name]=oid
return result
root_tree=tree(source,head)
report={'kind':'GiteaOfficialReferenceFingerprintProbe','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceHead':head,'sourceCommittedFiles':len(root_tree),'officialHistoryHead':'146cc3eec57174711eac0e0a0c7b38670c6e3922','liveSourceServiceDatabaseChanged':False,'method':'Exact Git blob fingerprints against bounded official first-parent history; reference selection does not assert ancestry'}
commits=git(official,'rev-list','--first-parent','--max-count=800','--before=2026-03-19T00:00:00Z','refs/tags/v1.27.3').decode().splitlines()
report['candidateCount']=len(commits)
def emit(stage):
report['stage']=stage;print('GITEA_OFFICIAL_REFERENCE_JSON '+json.dumps(report,separators=(',',':')),flush=True)
emit('COMPARING_PUBLIC_TREE_FINGERPRINTS')
ranked=[];start=time.monotonic()
for index,commit in enumerate(commits):
if time.monotonic()-start>240:break
official_tree=tree(official,commit)
matches=sum(official_tree.get(p)==h for p,h in root_tree.items())
shared=sum(p in official_tree for p in root_tree)
ranked.append({'commit':commit,'matchingSourceBlobs':matches,'sharedPaths':shared,'officialFiles':len(official_tree),'order':index})
if (index+1)%100==0:
report['comparedCount']=len(ranked);report['bestMatchesSoFar']=max(r['matchingSourceBlobs'] for r in ranked);emit('COMPARING_PUBLIC_TREE_FINGERPRINTS')
ranked.sort(key=lambda r:(-r['matchingSourceBlobs'],r['order']))
report['comparedCount']=len(ranked);report['searchCompleted']=len(ranked)==len(commits);report['elapsedSeconds']=round(time.monotonic()-start,3);report['topReferences']=ranked[:8]
if not ranked:raise RuntimeError('NO_PUBLIC_REFERENCES_COMPARED')
best=ranked[0];official_tree=tree(official,best['commit'])
diff=[]
for p in sorted(set(root_tree)|set(official_tree)):
if root_tree.get(p)==official_tree.get(p):continue
name=p.decode('utf-8',errors='replace')
sensitive=any(x in name.lower() for x in ['.env','secret','credential','password','.pem','.key'])
diff.append({'path':'SENSITIVE_PATH_NOT_EXPORTED' if sensitive else name,'status':'modified' if p in root_tree and p in official_tree else ('source-only' if p in root_tree else 'official-only')})
report['selectedReference']=best['commit']
report['selectedReferenceMetadata']=git(official,'show','-s','--format=%H %cI',best['commit']).decode().strip()
report['committedTreeDifferenceCount']=len(diff)
report['committedTreeDifferences']=diff[:150];report['differencesTruncated']=len(diff)>150
report['status']='REFERENCE_FINGERPRINT_COMPARISON_COMPLETE'
(work/'full-tree-difference.private.json').write_text(json.dumps(diff,indent=2)+'\n')
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('COMPLETE')
PY
shell: bash
timeout-minutes: "10"
permissions:
contents: read
...
|
inspect
|
null
|
["ubuntu-latest"]
|
37534
|
1
|
1793524164
|
1793524179
|
1793524163
|
1793524180
|
|
0
|
|
0
|
Edit
Delete
|
|
46074
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Static checks (locked engineering dependency)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
public-static:
name: Static checks (locked engineering dependency)
runs-on: ubuntu-latest
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Test image release credential preflight (synthetic credentials only)
run: node --test .github/scripts/test/*.test.mjs
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Governance checks (exact engineering package; public contracts dependencies)
run: |
pnpm check:module-imports
pnpm check:canonical-ids
pnpm check:code-sets
pnpm check:omni-platform
pnpm check:fact-pii
pnpm check:catalog
pnpm check:migration-decs
pnpm check:caddy
pnpm test
pnpm contracts:check:local
- name: Pack publishable packages (contracts + governance; no publish)
run: |
rm -rf dist-artifacts
pnpm --dir contracts build
pnpm --dir governance pack --pack-destination ../dist-artifacts
pnpm --dir contracts pack --pack-destination ../dist-artifacts
ls -la dist-artifacts
- if: always()
name: Upload package tarballs
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-packages-${{ env.CANDIDATE_TAG }}
path: dist-artifacts/*.tgz
retention-days: "30"
- if: always()
name: Upload public static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-public-static-${{ env.CANDIDATE_TAG }}
path: reports/*.latest.json
retention-days: "30"
timeout-minutes: "15"
permissions:
contents: read
...
|
public-static
|
null
|
["ubuntu-latest"]
|
37535
|
2
|
1793524212
|
1793524216
|
1793524210
|
1793524216
|
|
0
|
|
0
|
Edit
Delete
|
|
46075
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Static governance (repo root, private packages)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
37536
|
2
|
1793524216
|
1793524219
|
1793524210
|
1793524219
|
|
0
|
|
0
|
Edit
Delete
|
|
46076
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate clients for authority module unit imports (no database)
run: pnpm --dir runtime prisma:generate
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
37537
|
4
|
1793524221
|
1793524221
|
1793524210
|
1793524221
|
|
1
|
|
0
|
Edit
Delete
|
|
46077
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Port conformance (kernel / modules / clients)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
37538
|
4
|
1793524223
|
1793524223
|
1793524210
|
1793524223
|
|
1
|
|
0
|
Edit
Delete
|
|
46078
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
# Compose parses all services even for --no-deps redpanda and down.
# These unused service values deliberately cannot start a runtime.
PLATFORM_DEPLOYMENT_ENV: test
PLATFORM_RUNTIME_IMAGE: enterprise-platform/runtime:ci-not-started
PLATFORM_RUNTIME_DATABASE_RUNTIME_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_DATABASE_SYSTEM_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_REDIS_URL: redis://127.0.0.1:1/15
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and provision every module acceptance database
run: |
pnpm runtime:build:modules
node governance/prepare-module-databases.mjs
- name: Prepare mainline fixtures and verify identity ordinary-role databases
run: |
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Build isolated MinIO from pinned upstream source
run: docker build -t enterprise-platform/test-minio:a6c538c5 stack/test-minio
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Registry admission and central audit recovery
run: pnpm check:registry-admission
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Configuration snapshots, tenant isolation and remote SDK acceptance
run: pnpm acceptance:configuration
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Identity signing against isolated OpenBao Transit
run: pnpm identity:check:transit
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload workbench browser diagnostics
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-workbench-browser-${{ env.CANDIDATE_TAG }}
path: /tmp/platform-workbench-ui-*/
retention-days: "7"
- if: always()
name: Upload runtime and UI evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/configuration-runtime.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
reports/registry-admission.latest.json
reports/identity-transit.latest.json
reports/scope-http.latest.json
reports/scope-fact-sla.latest.json
reports/machine-revocation-sla.latest.json
reports/credential-m1-sla.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
37539
|
4
|
1793524225
|
1793524225
|
1793524210
|
1793524225
|
|
1
|
|
0
|
Edit
Delete
|
|
46079
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; shared runtime identity fixture dependencies)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Build shared identity fixture dependencies from this checkout
run: |
pnpm --dir runtime install --frozen-lockfile --filter @juhai/module-identity... --filter @juhai/client-identity --filter api-nestjs
pnpm --dir runtime --filter @juhai/module-identity prisma:generate
pnpm --dir runtime exec turbo run build --filter=@juhai/module-identity... --filter=@juhai/client-identity...
pnpm --dir identity --filter api-nestjs exec node -e "require('node:assert/strict').strictEqual(require('@juhai/module-kit'), require('../../../runtime/modules/kit'))"
- name: Provision ordinary owner for the isolated identity test database
run: |
psql "${DATABASE_URL%%\?*}" -v ON_ERROR_STOP=1 <<'SQL'
CREATE ROLE enterprise_idp_ci_rt LOGIN PASSWORD 'ci-test-only' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;
ALTER DATABASE enterprise_idp_ci OWNER TO enterprise_idp_ci_rt;
ALTER SCHEMA public OWNER TO enterprise_idp_ci_rt;
SQL
echo 'DATABASE_URL=postgresql://enterprise_idp_ci_rt:ci-test-only@127.0.0.1:5432/enterprise_idp_ci?schema=public' >> "$GITHUB_ENV"
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (single NestJS host, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (single NestJS host)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
37540
|
4
|
1793524227
|
1793524227
|
1793524210
|
1793524227
|
|
1
|
|
0
|
Edit
Delete
|
|
46080
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: https://github.com/sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
37541
|
4
|
1793524229
|
1793524229
|
1793524210
|
1793524229
|
|
1
|
|
0
|
Edit
Delete
|
|
46081
|
26774
|
116
|
5
|
ae4b0fddffe5ec3848a42ae9920aeb292cce0933
|
0
|
Release candidate verification + manifest
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${GITHUB_RUN_ATTEMPT}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Download image and full SBOM evidence for the same candidate
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-image-${{ env.CANDIDATE_TAG }}
path: reports
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ needs.image.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity","image"]...
|
["ubuntu-latest"]
|
37542
|
2
|
1793524231
|
1793524240
|
1793524210
|
1793524240
|
|
1
|
|
0
|
Edit
Delete
|
|
46082
|
26775
|
116
|
5
|
f213a196ad7e7b8e857045d36bf6977243ceaca1
|
0
|
analyze
|
1
|
name: Analyze complete Gitea customization from ve name: Analyze complete Gitea customization from verified reference
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-complete-customization.yml]
workflow_dispatch:
jobs:
analyze:
name: analyze
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Preserve all committed and working source differences in a private candidate
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, json, os, pathlib, shutil, socket, subprocess
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
work=base/('complete-analysis-'+runid);work.mkdir(mode=0o700)
live=pathlib.Path('/root/gitea-src');snapshot=base/'stage-26762'/'baseline-source'
history=base/'analysis-26765'/'candidate-source'
reference='d6496c61561d90f56f0b5ec3f75d4de8e36a5c9f';target='146cc3eec57174711eac0e0a0c7b38670c6e3922'
ranking=json.loads((base/'fingerprint-26773'/'receipt.json').read_text())
if ranking.get('selectedReference')!=reference or ranking.get('topReferences',[{}])[0].get('matchingSourceBlobs')!=5788 or not ranking.get('searchCompleted'):raise RuntimeError('VERIFIED_REFERENCE_REQUIRED')
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
def git(repo,*args,timeout=60):
return subprocess.run(['git','--no-optional-locks','-c','credential.helper=','-c','core.askPass=','-c','http.extraHeader=','-c','core.hooksPath=/dev/null','-C',str(repo),*args],env=env,capture_output=True,timeout=timeout)
if git(live,'rev-parse','HEAD').stdout.decode().strip()!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('LIVE_SOURCE_HEAD_CHANGED')
def fingerprint(root):
h=hashlib.sha256();count=0
for parent,dirs,files in os.walk(root):
dirs[:]=sorted(d for d in dirs if d not in ['.git','node_modules','.cache','.secrets','.evidence-private'])
for name in sorted(files):
if name.startswith('.env') or name.endswith(('.key','.pem')):continue
p=pathlib.Path(parent)/name
if p.is_symlink() or not p.is_file():continue
d=hashlib.sha256()
with open(p,'rb') as f:
for block in iter(lambda:f.read(1024*1024),b''):d.update(block)
h.update(str(p.relative_to(root)).encode()+b'\0'+d.digest());count+=1
return h.hexdigest(),count
expected='a5534f2aa03220a02efecac6753f0edcb99db7e8a3da323a1bac3390e2793d74'
if fingerprint(live)!=(expected,6064) or fingerprint(snapshot)!=(expected,6064):raise RuntimeError('LIVE_OR_SAVED_SOURCE_CHANGED')
report={'kind':'GiteaCompleteCustomizationAnalysis','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceFingerprint':expected,'referenceCommit':reference,'referenceMethod':'Exact file comparison reference; not a Git ancestor','upstreamCommit':target,'privateWorkspace':str(work),'liveSourceServiceDatabaseChanged':False}
def emit(stage):
report['stage']=stage;print('GITEA_COMPLETE_CUSTOMIZATION_JSON '+json.dumps(report,separators=(',',':')),flush=True)
emit('PREPARING_COMPLETE_CUSTOMIZATION')
candidate=work/'candidate-source'
r=git(work,'clone','--shared','--no-checkout',str(history),str(candidate))
if r.returncode:raise RuntimeError('PRIVATE_CANDIDATE_CLONE_FAILED')
r=git(candidate,'checkout','--detach',target)
if r.returncode:raise RuntimeError('FIXED_CANDIDATE_CHECKOUT_FAILED')
def names(repo,*args):
r=git(repo,*args)
if r.returncode:raise RuntimeError('SOURCE_PATH_INVENTORY_FAILED')
return {x for x in r.stdout.decode().splitlines() if x}
committed=names(history,'diff','--no-ext-diff','--no-textconv','--no-renames','--name-only',reference,'287bf811487c04cd90bcf07aa04905cbaf2e4c2d')
working=names(live,'diff','--no-ext-diff','--no-textconv','--no-renames','--name-only','HEAD')
untracked=names(live,'ls-files','--others','--exclude-standard')
ignored=names(live,'ls-files','--others','--ignored','--exclude-standard')
report['ignoredProductionGoFiles']=sorted(p for p in ignored if p.endswith('.go') and p.split('/',1)[0] in ['models','modules','routers','services'] and '/node_modules/' not in p)
report['snapshotOnlyEntries']=[];report['customizationMerge']=[]
merge=work/'merge-inputs';merge.mkdir(mode=0o700)
MISSING=object()
for number,name in enumerate(sorted(committed|working|untracked)):
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts:raise RuntimeError('UNSAFE_SOURCE_PATH')
if not rel.parts or rel.parts[0] not in ['models','modules','routers','services','templates','options']:
if name=='IMPLEMENTATION_PLAN.md':report['implementationPlanRetainedInBaseline']=True
report['snapshotOnlyEntries'].append(name if not any(x in name.lower() for x in ['.env','secret','credential','password','.pem','.key']) else 'SENSITIVE_PATH_NOT_EXPORTED')
continue
if name.startswith('models/migrations/'):
report['customizationMerge'].append({'path':name,'status':'HELD_FOR_EXPLICIT_MIGRATION_BRIDGE'});continue
p=snapshot/name;out=candidate/name
if p.is_symlink() or out.is_symlink():raise RuntimeError('SYMLINK_CUSTOMIZATION_REVIEW_REQUIRED')
rc,base_blob=git(history,'show',reference+':'+name)
ancestor=base_blob.replace(b'code.gitea.io/gitea',b'gitea.dev') if rc==0 else None
theirs=p.read_bytes().replace(b'code.gitea.io/gitea',b'gitea.dev') if p.is_file() else None
ours=out.read_bytes() if out.is_file() else None
state=None
if theirs==ancestor:state='UPSTREAM_UPDATE_RETAINED_NO_CUSTOM_DELTA'
elif ours==theirs:state='ALREADY_IDENTICAL'
elif ancestor is None and ours is None and theirs is not None:
out.parent.mkdir(parents=True,exist_ok=True);out.write_bytes(theirs);state='CUSTOM_ADDITION_PRESERVED'
elif theirs is None:
if ours==ancestor:
out.unlink();state='CUSTOM_DELETION_PRESERVED'
else:state='DELETE_MODIFY_REVIEW_REQUIRED'
elif ours is None:state='UPSTREAM_DELETION_REVIEW_REQUIRED'
elif name.startswith('options/locale/') and name.endswith('.json'):
b=json.loads(ancestor) if ancestor is not None else {};o=json.loads(ours);t=json.loads(theirs)
if not all(isinstance(v,dict) for v in [b,o,t]):raise RuntimeError('LOCALE_OBJECT_REQUIRED')
result=dict(o);conflicts=[]
for key in set(b)|set(t):
bv=b.get(key,MISSING);ov=o.get(key,MISSING);tv=t.get(key,MISSING)
if tv==bv:continue
if ov==bv or ov==tv:
if tv is MISSING:result.pop(key,None)
else:result[key]=tv
else:conflicts.append(key)
if conflicts:state='SEMANTIC_REVIEW_REQUIRED';report.setdefault('localeConflictKeys',{})[name]=sorted(conflicts)
else:
out.write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n');state='LOCALE_THREE_WAY_KEYS_MERGED'
elif ancestor is None:state='ADD_ADD_REVIEW_REQUIRED'
else:
a=merge/(str(number)+'.ours');b=merge/(str(number)+'.base');c=merge/(str(number)+'.theirs')
a.write_bytes(ours);b.write_bytes(ancestor);c.write_bytes(theirs)
r=git(work,'merge-file','-p',str(a),str(b),str(c))
if r.returncode==0:out.write_bytes(r.stdout);state='TEXTUAL_MERGE_CLEAN_SEMANTICS_UNVERIFIED'
else:
(merge/(str(number)+'.conflicted')).write_bytes(r.stdout);state='SEMANTIC_REVIEW_REQUIRED'
report['customizationMerge'].append({'path':name,'status':state})
report['status']='COMPLETE_COMMITTED_AND_WORKING_CUSTOMIZATION_ANALYZED'
report['candidateBuilt']=False;report['candidateMigrated']=False
if fingerprint(live)!=(expected,6064):raise RuntimeError('LIVE_SOURCE_CHANGED_DURING_ANALYSIS')
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('COMPLETE')
PY
shell: bash
timeout-minutes: "10"
permissions:
contents: read
...
|
analyze
|
null
|
["ubuntu-latest"]
|
37543
|
2
|
1793524457
|
1793524470
|
1793524455
|
1793524470
|
|
0
|
|
0
|
Edit
Delete
|
|
46083
|
26776
|
116
|
5
|
4d50038a152fa8e9392fc904b941be90317651ec
|
0
|
analyze
|
1
|
name: Analyze complete Gitea customization from ve name: Analyze complete Gitea customization from verified reference
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-complete-customization.yml]
workflow_dispatch:
jobs:
analyze:
name: analyze
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Preserve all committed and working source differences in a private candidate
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, json, os, pathlib, shutil, socket, subprocess
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
work=base/('complete-analysis-'+runid);work.mkdir(mode=0o700)
live=pathlib.Path('/root/gitea-src');snapshot=base/'stage-26762'/'baseline-source'
history=base/'analysis-26765'/'candidate-source'
reference='d6496c61561d90f56f0b5ec3f75d4de8e36a5c9f';target='146cc3eec57174711eac0e0a0c7b38670c6e3922'
ranking=json.loads((base/'fingerprint-26773'/'receipt.json').read_text())
if ranking.get('selectedReference')!=reference or ranking.get('topReferences',[{}])[0].get('matchingSourceBlobs')!=5788 or not ranking.get('searchCompleted'):raise RuntimeError('VERIFIED_REFERENCE_REQUIRED')
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
def git(repo,*args,timeout=60):
return subprocess.run(['git','--no-optional-locks','-c','credential.helper=','-c','core.askPass=','-c','http.extraHeader=','-c','core.hooksPath=/dev/null','-C',str(repo),*args],env=env,capture_output=True,timeout=timeout)
if git(live,'rev-parse','HEAD').stdout.decode().strip()!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('LIVE_SOURCE_HEAD_CHANGED')
def fingerprint(root):
h=hashlib.sha256();count=0
for parent,dirs,files in os.walk(root):
dirs[:]=sorted(d for d in dirs if d not in ['.git','node_modules','.cache','.secrets','.evidence-private'])
for name in sorted(files):
if name.startswith('.env') or name.endswith(('.key','.pem')):continue
p=pathlib.Path(parent)/name
if p.is_symlink() or not p.is_file():continue
d=hashlib.sha256()
with open(p,'rb') as f:
for block in iter(lambda:f.read(1024*1024),b''):d.update(block)
h.update(str(p.relative_to(root)).encode()+b'\0'+d.digest());count+=1
return h.hexdigest(),count
expected='a5534f2aa03220a02efecac6753f0edcb99db7e8a3da323a1bac3390e2793d74'
if fingerprint(live)!=(expected,6064) or fingerprint(snapshot)!=(expected,6064):raise RuntimeError('LIVE_OR_SAVED_SOURCE_CHANGED')
report={'kind':'GiteaCompleteCustomizationAnalysis','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceFingerprint':expected,'referenceCommit':reference,'referenceMethod':'Exact file comparison reference; not a Git ancestor','upstreamCommit':target,'privateWorkspace':str(work),'liveSourceServiceDatabaseChanged':False}
def emit(stage):
report['stage']=stage;print('GITEA_COMPLETE_CUSTOMIZATION_JSON '+json.dumps(report,separators=(',',':')),flush=True)
emit('PREPARING_COMPLETE_CUSTOMIZATION')
candidate=work/'candidate-source'
r=git(work,'clone','--shared','--no-checkout',str(history),str(candidate))
if r.returncode:raise RuntimeError('PRIVATE_CANDIDATE_CLONE_FAILED')
r=git(candidate,'checkout','--detach',target)
if r.returncode:raise RuntimeError('FIXED_CANDIDATE_CHECKOUT_FAILED')
def names(repo,*args):
r=git(repo,*args)
if r.returncode:raise RuntimeError('SOURCE_PATH_INVENTORY_FAILED')
return {x for x in r.stdout.decode().splitlines() if x}
committed=names(history,'diff','--no-ext-diff','--no-textconv','--no-renames','--name-only',reference,'287bf811487c04cd90bcf07aa04905cbaf2e4c2d')
working=names(live,'diff','--no-ext-diff','--no-textconv','--no-renames','--name-only','HEAD')
untracked=names(live,'ls-files','--others','--exclude-standard')
ignored=names(live,'ls-files','--others','--ignored','--exclude-standard')
report['ignoredProductionGoFiles']=sorted(p for p in ignored if p.endswith('.go') and p.split('/',1)[0] in ['models','modules','routers','services'] and '/node_modules/' not in p)
report['snapshotOnlyEntries']=[];report['customizationMerge']=[]
merge=work/'merge-inputs';merge.mkdir(mode=0o700)
MISSING=object()
for number,name in enumerate(sorted(committed|working|untracked)):
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts:raise RuntimeError('UNSAFE_SOURCE_PATH')
if not rel.parts or rel.parts[0] not in ['models','modules','routers','services','templates','options']:
if name=='IMPLEMENTATION_PLAN.md':report['implementationPlanRetainedInBaseline']=True
report['snapshotOnlyEntries'].append(name if not any(x in name.lower() for x in ['.env','secret','credential','password','.pem','.key']) else 'SENSITIVE_PATH_NOT_EXPORTED')
continue
if name.startswith('models/migrations/'):
report['customizationMerge'].append({'path':name,'status':'HELD_FOR_EXPLICIT_MIGRATION_BRIDGE'});continue
p=snapshot/name;out=candidate/name
if p.is_symlink() or out.is_symlink():raise RuntimeError('SYMLINK_CUSTOMIZATION_REVIEW_REQUIRED')
original=git(history,'show',reference+':'+name)
ancestor=original.stdout.replace(b'code.gitea.io/gitea',b'gitea.dev') if original.returncode==0 else None
theirs=p.read_bytes().replace(b'code.gitea.io/gitea',b'gitea.dev') if p.is_file() else None
ours=out.read_bytes() if out.is_file() else None
state=None
if theirs==ancestor:state='UPSTREAM_UPDATE_RETAINED_NO_CUSTOM_DELTA'
elif ours==theirs:state='ALREADY_IDENTICAL'
elif ancestor is None and ours is None and theirs is not None:
out.parent.mkdir(parents=True,exist_ok=True);out.write_bytes(theirs);state='CUSTOM_ADDITION_PRESERVED'
elif theirs is None:
if ours==ancestor:
out.unlink();state='CUSTOM_DELETION_PRESERVED'
else:state='DELETE_MODIFY_REVIEW_REQUIRED'
elif ours is None:state='UPSTREAM_DELETION_REVIEW_REQUIRED'
elif name.startswith('options/locale/') and name.endswith('.json'):
b=json.loads(ancestor) if ancestor is not None else {};o=json.loads(ours);t=json.loads(theirs)
if not all(isinstance(v,dict) for v in [b,o,t]):raise RuntimeError('LOCALE_OBJECT_REQUIRED')
result=dict(o);conflicts=[]
for key in set(b)|set(t):
bv=b.get(key,MISSING);ov=o.get(key,MISSING);tv=t.get(key,MISSING)
if tv==bv:continue
if ov==bv or ov==tv:
if tv is MISSING:result.pop(key,None)
else:result[key]=tv
else:conflicts.append(key)
if conflicts:state='SEMANTIC_REVIEW_REQUIRED';report.setdefault('localeConflictKeys',{})[name]=sorted(conflicts)
else:
out.write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n');state='LOCALE_THREE_WAY_KEYS_MERGED'
elif ancestor is None:state='ADD_ADD_REVIEW_REQUIRED'
else:
a=merge/(str(number)+'.ours');b=merge/(str(number)+'.base');c=merge/(str(number)+'.theirs')
a.write_bytes(ours);b.write_bytes(ancestor);c.write_bytes(theirs)
r=git(work,'merge-file','-p',str(a),str(b),str(c))
if r.returncode==0:out.write_bytes(r.stdout);state='TEXTUAL_MERGE_CLEAN_SEMANTICS_UNVERIFIED'
else:
(merge/(str(number)+'.conflicted')).write_bytes(r.stdout);state='SEMANTIC_REVIEW_REQUIRED'
report['customizationMerge'].append({'path':name,'status':state})
report['status']='COMPLETE_COMMITTED_AND_WORKING_CUSTOMIZATION_ANALYZED'
report['candidateBuilt']=False;report['candidateMigrated']=False
if fingerprint(live)!=(expected,6064):raise RuntimeError('LIVE_SOURCE_CHANGED_DURING_ANALYSIS')
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('COMPLETE')
PY
shell: bash
timeout-minutes: "10"
permissions:
contents: read
...
|
analyze
|
null
|
["ubuntu-latest"]
|
37544
|
2
|
1793524562
|
1793524628
|
1793524560
|
1793524629
|
|
0
|
|
0
|
Edit
Delete
|
|
46084
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Static checks (locked engineering dependency)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
public-static:
name: Static checks (locked engineering dependency)
runs-on: ubuntu-latest
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Test image release credential preflight (synthetic credentials only)
run: node --test .github/scripts/test/*.test.mjs
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Governance checks (exact engineering package; public contracts dependencies)
run: |
pnpm check:module-imports
pnpm check:canonical-ids
pnpm check:code-sets
pnpm check:omni-platform
pnpm check:fact-pii
pnpm check:catalog
pnpm check:migration-decs
pnpm check:caddy
pnpm test
pnpm contracts:check:local
- name: Pack publishable packages (contracts + governance; no publish)
run: |
rm -rf dist-artifacts
pnpm --dir contracts build
pnpm --dir governance pack --pack-destination ../dist-artifacts
pnpm --dir contracts pack --pack-destination ../dist-artifacts
ls -la dist-artifacts
- if: always()
name: Upload package tarballs
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-packages-${{ env.CANDIDATE_TAG }}
path: dist-artifacts/*.tgz
retention-days: "30"
- if: always()
name: Upload public static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-public-static-${{ env.CANDIDATE_TAG }}
path: reports/*.latest.json
retention-days: "30"
timeout-minutes: "15"
permissions:
contents: read
...
|
public-static
|
null
|
["ubuntu-latest"]
|
37545
|
2
|
1793524733
|
1793524737
|
1793524732
|
1793524737
|
|
0
|
|
0
|
Edit
Delete
|
|
46085
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Static governance (repo root, private packages)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
37546
|
2
|
1793524737
|
1793524796
|
1793524732
|
1793524797
|
|
0
|
|
0
|
Edit
Delete
|
|
46086
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate clients for authority module unit imports (no database)
run: pnpm --dir runtime prisma:generate
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
37547
|
4
|
1793524799
|
1793524799
|
1793524732
|
1793524799
|
|
1
|
|
0
|
Edit
Delete
|
|
46087
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Port conformance (kernel / modules / clients)
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
37548
|
4
|
1793524801
|
1793524801
|
1793524732
|
1793524801
|
|
1
|
|
0
|
Edit
Delete
|
|
46088
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
# Compose parses all services even for --no-deps redpanda and down.
# These unused service values deliberately cannot start a runtime.
PLATFORM_DEPLOYMENT_ENV: test
PLATFORM_RUNTIME_IMAGE: enterprise-platform/runtime:ci-not-started
PLATFORM_RUNTIME_DATABASE_RUNTIME_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_DATABASE_SYSTEM_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_REDIS_URL: redis://127.0.0.1:1/15
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and provision every module acceptance database
run: |
pnpm runtime:build:modules
node governance/prepare-module-databases.mjs
- name: Prepare mainline fixtures and verify identity ordinary-role databases
run: |
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Build isolated MinIO from pinned upstream source
run: docker build -t enterprise-platform/test-minio:a6c538c5 stack/test-minio
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Registry admission and central audit recovery
run: pnpm check:registry-admission
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Configuration snapshots, tenant isolation and remote SDK acceptance
run: pnpm acceptance:configuration
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Identity signing against isolated OpenBao Transit
run: pnpm identity:check:transit
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload workbench browser diagnostics
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-workbench-browser-${{ env.CANDIDATE_TAG }}
path: /tmp/platform-workbench-ui-*/
retention-days: "7"
- if: always()
name: Upload runtime and UI evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/configuration-runtime.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
reports/registry-admission.latest.json
reports/identity-transit.latest.json
reports/scope-http.latest.json
reports/scope-fact-sla.latest.json
reports/machine-revocation-sla.latest.json
reports/credential-m1-sla.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
37549
|
4
|
1793524803
|
1793524803
|
1793524732
|
1793524803
|
|
1
|
|
0
|
Edit
Delete
|
|
46089
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; shared runtime identity fixture dependencies)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Build shared identity fixture dependencies from this checkout
run: |
pnpm --dir runtime install --frozen-lockfile --filter @juhai/module-identity... --filter @juhai/client-identity --filter api-nestjs
pnpm --dir runtime --filter @juhai/module-identity prisma:generate
pnpm --dir runtime exec turbo run build --filter=@juhai/module-identity... --filter=@juhai/client-identity...
pnpm --dir identity --filter api-nestjs exec node -e "require('node:assert/strict').strictEqual(require('@juhai/module-kit'), require('../../../runtime/modules/kit'))"
- name: Provision ordinary owner for the isolated identity test database
run: |
psql "${DATABASE_URL%%\?*}" -v ON_ERROR_STOP=1 <<'SQL'
CREATE ROLE enterprise_idp_ci_rt LOGIN PASSWORD 'ci-test-only' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;
ALTER DATABASE enterprise_idp_ci OWNER TO enterprise_idp_ci_rt;
ALTER SCHEMA public OWNER TO enterprise_idp_ci_rt;
SQL
echo 'DATABASE_URL=postgresql://enterprise_idp_ci_rt:ci-test-only@127.0.0.1:5432/enterprise_idp_ci?schema=public' >> "$GITHUB_ENV"
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (single NestJS host, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (single NestJS host)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
37550
|
4
|
1793524805
|
1793524805
|
1793524732
|
1793524805
|
|
1
|
|
0
|
Edit
Delete
|
|
46090
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: https://github.com/sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
37551
|
4
|
1793524807
|
1793524807
|
1793524732
|
1793524807
|
|
1
|
|
0
|
Edit
Delete
|
|
46091
|
26777
|
116
|
5
|
7969dbb47cfa5bbb57530516484846c5dd355167
|
0
|
Release candidate verification + manifest
|
1
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
candidate:
name: Release candidate verification + manifest
runs-on: ubuntu-latest
if: always()
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Download static evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-static-${{ env.CANDIDATE_TAG }}
path: candidate/static
continue-on-error: true
- name: Download runtime evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: candidate/runtime/runtime/reports
continue-on-error: true
- name: Download identity evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: candidate/identity/identity/reports
continue-on-error: true
- name: Download port-conformance evidence
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: candidate/port-conformance/reports
continue-on-error: true
- id: verify
name: Verify candidate (per-report sourceSha / dirty / status / digest; missing → ineligible)
run: node governance/verify-candidate.mjs --candidate candidate --sha "${{ github.sha }}" --run-id "${{ github.run_id }}" --attempt "${GITHUB_RUN_ATTEMPT}" --out reports/release-candidate.latest.json
continue-on-error: true
- name: Download image and full SBOM evidence for the same candidate
uses: https://github.com/actions/download-artifact@v3
with:
name: platform-image-${{ env.CANDIDATE_TAG }}
path: reports
- name: Release Manifest (known facts, status partial until all deliverables exist)
run: node governance/release-manifest.mjs
- if: always()
name: Upload candidate evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-candidate-${{ env.CANDIDATE_TAG }}
path: |
reports/release-candidate.latest.json
reports/release-manifest.latest.json
retention-days: "30"
- if: always()
name: Propagate upstream results and candidate eligibility
run: |
echo "public-static=${{ needs.public-static.result }} static=${{ needs.static.result }} runtime=${{ needs.runtime.result }} identity=${{ needs.identity.result }} verify=${{ steps.verify.outcome }}"
test "${{ needs.public-static.result }}" = "success"
test "${{ needs.static.result }}" = "success"
test "${{ needs.unit.result }}" = "success"
test "${{ needs.port-conformance.result }}" = "success"
test "${{ needs.runtime.result }}" = "success"
test "${{ needs.identity.result }}" = "success"
test "${{ needs.image.result }}" = "success"
test "${{ steps.verify.outcome }}" = "success"
timeout-minutes: "10"
permissions:
contents: read
...
|
candidate
|
["public-static","static","uni ["public-static","static","unit","port-conformance","runtime","identity","image"]...
|
["ubuntu-latest"]
|
37552
|
2
|
1793524809
|
1793524839
|
1793524732
|
1793524839
|
|
1
|
|
0
|
Edit
Delete
|
|
46092
|
26778
|
116
|
5
|
68b62aa8581bdd0cd72b21110405e56ef57975ee
|
0
|
analyze
|
1
|
name: Analyze complete Gitea customization from ve name: Analyze complete Gitea customization from verified reference
"on":
push:
branches: [codex/runner-maintenance-diagnostic-20261101]
paths: [.gitea/workflows/gitea-complete-customization.yml]
workflow_dispatch:
jobs:
analyze:
name: analyze
runs-on: ubuntu-latest
if: github.repository == 'luoanwu/enterprise-platform'
steps:
- name: Preserve all committed and working source differences in a private candidate
run: |
set -eu
python3 <<'PY'
import datetime, hashlib, io, json, os, pathlib, re, shutil, socket, subprocess, tarfile
if os.geteuid()!=0 or socket.gethostname()!='iZ2zed3pt2nygf9dy1a9d2Z':raise RuntimeError('EXPECTED_HOST_REQUIRED')
os.umask(0o077)
base=pathlib.Path('/var/lib/eios-r1-maintenance')
if base.is_symlink() or not base.is_dir() or base.stat().st_uid!=0 or base.stat().st_mode&0o077:raise RuntimeError('PRIVATE_BASE_REQUIRED')
runid=os.environ.get('GITHUB_RUN_ID')
if not runid or not runid.isdigit():raise RuntimeError('REAL_RUN_ID_REQUIRED')
work=base/('complete-analysis-'+runid);work.mkdir(mode=0o700)
live=pathlib.Path('/root/gitea-src');snapshot=base/'stage-26762'/'baseline-source'
history=base/'analysis-26765'/'candidate-source'
reference='d6496c61561d90f56f0b5ec3f75d4de8e36a5c9f';target='146cc3eec57174711eac0e0a0c7b38670c6e3922'
ranking=json.loads((base/'fingerprint-26773'/'receipt.json').read_text())
if ranking.get('selectedReference')!=reference or ranking.get('topReferences',[{}])[0].get('matchingSourceBlobs')!=5788 or not ranking.get('searchCompleted'):raise RuntimeError('VERIFIED_REFERENCE_REQUIRED')
env={'PATH':'/usr/local/bin:/usr/bin:/bin','HOME':str(work),'LANG':'C.UTF-8','GIT_CONFIG_NOSYSTEM':'1','GIT_CONFIG_GLOBAL':'/dev/null','GIT_TERMINAL_PROMPT':'0','GIT_OPTIONAL_LOCKS':'0'}
def git(repo,*args,timeout=60):
return subprocess.run(['git','--no-optional-locks','-c','safe.directory=/home/git/repositories/luoanwu/enterprise-platform.git','-c','credential.helper=','-c','core.askPass=','-c','http.extraHeader=','-c','core.hooksPath=/dev/null','-C',str(repo),*args],env=env,capture_output=True,timeout=timeout)
if git(live,'rev-parse','HEAD').stdout.decode().strip()!='287bf811487c04cd90bcf07aa04905cbaf2e4c2d':raise RuntimeError('LIVE_SOURCE_HEAD_CHANGED')
def fingerprint(root):
h=hashlib.sha256();count=0
for parent,dirs,files in os.walk(root):
dirs[:]=sorted(d for d in dirs if d not in ['.git','node_modules','.cache','.secrets','.evidence-private'])
for name in sorted(files):
if name.startswith('.env') or name.endswith(('.key','.pem')):continue
p=pathlib.Path(parent)/name
if p.is_symlink() or not p.is_file():continue
d=hashlib.sha256()
with open(p,'rb') as f:
for block in iter(lambda:f.read(1024*1024),b''):d.update(block)
h.update(str(p.relative_to(root)).encode()+b'\0'+d.digest());count+=1
return h.hexdigest(),count
expected='a5534f2aa03220a02efecac6753f0edcb99db7e8a3da323a1bac3390e2793d74'
if fingerprint(live)!=(expected,6064) or fingerprint(snapshot)!=(expected,6064):raise RuntimeError('LIVE_OR_SAVED_SOURCE_CHANGED')
report={'kind':'GiteaCompleteCustomizationAnalysis','observedAtUTC':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ci':{'sourceSha':os.environ.get('GITHUB_SHA'),'runId':runid},'releaseEligible':False,'sourceFingerprint':expected,'referenceCommit':reference,'referenceMethod':'Exact file comparison reference; not a Git ancestor','upstreamCommit':target,'privateWorkspace':str(work),'liveSourceServiceDatabaseChanged':False}
def emit(stage):
report['stage']=stage;print('GITEA_COMPLETE_CUSTOMIZATION_JSON '+json.dumps(report,separators=(',',':')),flush=True)
emit('PREPARING_COMPLETE_CUSTOMIZATION')
candidate=work/'candidate-source'
r=git(work,'clone','--shared','--no-checkout',str(history),str(candidate))
if r.returncode:raise RuntimeError('PRIVATE_CANDIDATE_CLONE_FAILED')
r=git(candidate,'checkout','--detach',target)
if r.returncode:raise RuntimeError('FIXED_CANDIDATE_CHECKOUT_FAILED')
def names(repo,*args):
r=git(repo,*args)
if r.returncode:raise RuntimeError('SOURCE_PATH_INVENTORY_FAILED')
return {x for x in r.stdout.decode().splitlines() if x}
committed=names(history,'diff','--no-ext-diff','--no-textconv','--no-renames','--name-only',reference,'287bf811487c04cd90bcf07aa04905cbaf2e4c2d')
working=names(live,'diff','--no-ext-diff','--no-textconv','--no-renames','--name-only','HEAD')
untracked=names(live,'ls-files','--others','--exclude-standard')
ignored=names(live,'ls-files','--others','--ignored','--exclude-standard')
source_sha=os.environ.get('GITHUB_SHA','')
if not re.fullmatch(r'[0-9a-f]{40}',source_sha):raise RuntimeError('FIXED_JOB_SOURCE_SHA_REQUIRED')
bare=pathlib.Path('/home/git/repositories/luoanwu/enterprise-platform.git')
if bare.is_symlink() or not bare.is_dir():raise RuntimeError('EXPECTED_SOURCE_REPOSITORY_REQUIRED')
packed=git(bare,'show',source_sha+':ops/gitea-r1/upstream-reference-d6496c6.tar.gz')
if packed.returncode or hashlib.sha256(packed.stdout).hexdigest()!='a7d3f17e4810eca2294cf110790a6332d0681c909b2393b3a2ae20455c3a2322':raise RuntimeError('PUBLIC_REFERENCE_ARCHIVE_MISMATCH')
listing=git(history,'ls-tree','-r','-z','--format=%(objecttype) %(objectname) %(path)',reference)
if listing.returncode:raise RuntimeError('OFFICIAL_REFERENCE_TREE_UNAVAILABLE')
reference_tree={}
for row in listing.stdout.split(b'\0'):
if not row:continue
kind,oid,path=row.split(b' ',2)
if kind==b'blob':reference_tree[path.decode()]=oid.decode()
public_base={}
with tarfile.open(fileobj=io.BytesIO(packed.stdout),mode='r:gz') as archive:
members=archive.getmembers()
if len({m.name for m in members})!=len(members) or not all(m.isfile() and m.size<=2*1024*1024 for m in members) or sum(m.size for m in members)>8*1024*1024:raise RuntimeError('REFERENCE_ARCHIVE_STRUCTURE_REFUSED')
manifest=json.loads(archive.extractfile('manifest.json').read())
if manifest.get('referenceCommit')!=reference or manifest.get('upstreamRepository')!='https://github.com/go-gitea/gitea':raise RuntimeError('PUBLIC_REFERENCE_SOURCE_MISMATCH')
if {m.name for m in members}!={'manifest.json','LICENSE.upstream'}|{'files/'+v['path'] for v in manifest['files']}:raise RuntimeError('REFERENCE_ARCHIVE_MEMBER_MISMATCH')
for item in manifest['files']:
name=item['path'];part=pathlib.PurePosixPath(name)
if part.is_absolute() or '..' in part.parts:raise RuntimeError('REFERENCE_PATH_REFUSED')
body=archive.extractfile('files/'+name).read()
oid=hashlib.sha1(b'blob '+str(len(body)).encode()+b'\0'+body).hexdigest()
if oid!=reference_tree.get(name) or oid!=item['gitBlob'] or hashlib.sha256(body).hexdigest()!=item['sha256'] or len(body)!=item['bytes']:raise RuntimeError('OFFICIAL_REFERENCE_BLOB_MISMATCH')
public_base[name]=body
report['publicReferenceInput']={'sourceSha':source_sha,'archiveSha256':hashlib.sha256(packed.stdout).hexdigest(),'filesVerifiedAgainstOfficialGitTree':len(public_base),'historicalBlobNetworkRequired':False}
report['ignoredProductionGoFiles']=sorted(p for p in ignored if p.endswith('.go') and p.split('/',1)[0] in ['models','modules','routers','services'] and '/node_modules/' not in p)
report['snapshotOnlyEntries']=[];report['customizationMerge']=[]
merge=work/'merge-inputs';merge.mkdir(mode=0o700)
MISSING=object()
for number,name in enumerate(sorted(committed|working|untracked)):
rel=pathlib.PurePosixPath(name)
if rel.is_absolute() or '..' in rel.parts:raise RuntimeError('UNSAFE_SOURCE_PATH')
if not rel.parts or rel.parts[0] not in ['models','modules','routers','services','templates','options']:
if name=='IMPLEMENTATION_PLAN.md':report['implementationPlanRetainedInBaseline']=True
report['snapshotOnlyEntries'].append(name if not any(x in name.lower() for x in ['.env','secret','credential','password','.pem','.key']) else 'SENSITIVE_PATH_NOT_EXPORTED')
continue
if name.startswith('models/migrations/'):
report['customizationMerge'].append({'path':name,'status':'HELD_FOR_EXPLICIT_MIGRATION_BRIDGE'});continue
p=snapshot/name;out=candidate/name
if p.is_symlink() or out.is_symlink():raise RuntimeError('SYMLINK_CUSTOMIZATION_REVIEW_REQUIRED')
if name in reference_tree and name not in public_base:raise RuntimeError('PUBLIC_REFERENCE_INPUT_PATH_MISSING')
ancestor=public_base[name].replace(b'code.gitea.io/gitea',b'gitea.dev') if name in public_base else None
theirs=p.read_bytes().replace(b'code.gitea.io/gitea',b'gitea.dev') if p.is_file() else None
ours=out.read_bytes() if out.is_file() else None
state=None
if theirs==ancestor:state='UPSTREAM_UPDATE_RETAINED_NO_CUSTOM_DELTA'
elif ours==theirs:state='ALREADY_IDENTICAL'
elif ancestor is None and ours is None and theirs is not None:
out.parent.mkdir(parents=True,exist_ok=True);out.write_bytes(theirs);state='CUSTOM_ADDITION_PRESERVED'
elif theirs is None:
if ours==ancestor:
out.unlink();state='CUSTOM_DELETION_PRESERVED'
else:state='DELETE_MODIFY_REVIEW_REQUIRED'
elif ours is None:state='UPSTREAM_DELETION_REVIEW_REQUIRED'
elif name.startswith('options/locale/') and name.endswith('.json'):
b=json.loads(ancestor) if ancestor is not None else {};o=json.loads(ours);t=json.loads(theirs)
if not all(isinstance(v,dict) for v in [b,o,t]):raise RuntimeError('LOCALE_OBJECT_REQUIRED')
result=dict(o);conflicts=[]
for key in set(b)|set(t):
bv=b.get(key,MISSING);ov=o.get(key,MISSING);tv=t.get(key,MISSING)
if tv==bv:continue
if ov==bv or ov==tv:
if tv is MISSING:result.pop(key,None)
else:result[key]=tv
else:conflicts.append(key)
if conflicts:state='SEMANTIC_REVIEW_REQUIRED';report.setdefault('localeConflictKeys',{})[name]=sorted(conflicts)
else:
out.write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n');state='LOCALE_THREE_WAY_KEYS_MERGED'
elif ancestor is None:state='ADD_ADD_REVIEW_REQUIRED'
else:
a=merge/(str(number)+'.ours');b=merge/(str(number)+'.base');c=merge/(str(number)+'.theirs')
a.write_bytes(ours);b.write_bytes(ancestor);c.write_bytes(theirs)
r=git(work,'merge-file','-p',str(a),str(b),str(c))
if r.returncode==0:out.write_bytes(r.stdout);state='TEXTUAL_MERGE_CLEAN_SEMANTICS_UNVERIFIED'
else:
(merge/(str(number)+'.conflicted')).write_bytes(r.stdout);state='SEMANTIC_REVIEW_REQUIRED'
report['customizationMerge'].append({'path':name,'status':state})
report['status']='COMPLETE_COMMITTED_AND_WORKING_CUSTOMIZATION_ANALYZED'
report['candidateBuilt']=False;report['candidateMigrated']=False
if fingerprint(live)!=(expected,6064):raise RuntimeError('LIVE_SOURCE_CHANGED_DURING_ANALYSIS')
(work/'receipt.json').write_text(json.dumps(report,indent=2)+'\n')
emit('COMPLETE')
PY
shell: bash
timeout-minutes: "10"
permissions:
contents: read
...
|
analyze
|
null
|
["ubuntu-latest"]
|
37553
|
1
|
1793525015
|
1793525024
|
1793525014
|
1793525024
|
|
0
|
|
0
|
Edit
Delete
|
|
46093
|
26779
|
117
|
5
|
86bed4a3e1de34c4baa3ac9fa5dc10782d849b52
|
0
|
Governance tests (report-only until act_runner is Governance tests (report-only until act_runner is enabled)...
|
1
|
name: Governance
"on":
push:
b name: Governance
"on":
push:
branches: [main]
pull_request:
workflow_dispatch:
env:
FOUNDATION_REPORT_DIR: ${{ runner.temp }}/foundation-reports
PNPM_VERSION: 9.15.9
jobs:
governance-tests:
name: Governance tests (report-only until act_runner is enabled)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: Governance tests
run: pnpm --dir 平台治理/基础 test
continue-on-error: true
- name: Governance gates (all gates run to completion; not blocking yet)
run: pnpm --dir 平台治理/基础 check
continue-on-error: true
- name: Tracked-secrets gate (root scope; the only gate whose CI result is meaningful without nested repos)
run: node 平台治理/基础/scripts/check-tracked-secrets.mjs --scope=root
timeout-minutes: "20"
permissions:
contents: read
...
|
governance-tests
|
null
|
["ubuntu-latest"]
|
37554
|
2
|
1793525369
|
1793525798
|
1793525367
|
1793525798
|
|
0
|
|
0
|
Edit
Delete
|
|
46094
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
Static checks (locked engineering dependency)
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
public-static:
name: Static checks (locked engineering dependency)
runs-on: ubuntu-latest
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Test image release credential preflight (synthetic credentials only)
run: node --test .github/scripts/test/*.test.mjs
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Governance checks (exact engineering package; public contracts dependencies)
run: |
pnpm check:module-imports
pnpm check:canonical-ids
pnpm check:code-sets
pnpm check:omni-platform
pnpm check:fact-pii
pnpm check:catalog
pnpm check:migration-decs
pnpm check:caddy
pnpm test
pnpm contracts:check:local
- name: Pack publishable packages (contracts + governance; no publish)
run: |
rm -rf dist-artifacts
pnpm --dir contracts build
pnpm --dir governance pack --pack-destination ../dist-artifacts
pnpm --dir contracts pack --pack-destination ../dist-artifacts
ls -la dist-artifacts
- if: always()
name: Upload package tarballs
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-packages-${{ env.CANDIDATE_TAG }}
path: dist-artifacts/*.tgz
retention-days: "30"
- if: always()
name: Upload public static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-public-static-${{ env.CANDIDATE_TAG }}
path: reports/*.latest.json
retention-days: "30"
timeout-minutes: "15"
permissions:
contents: read
...
|
public-static
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|
|
46095
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
Static governance (repo root, private packages)
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
static:
name: Static governance (repo root, private packages)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install contracts dependencies (public npm only, frozen lockfile; CT-1 build / validators / generated-types check)
run: pnpm --dir contracts install --frozen-lockfile
- name: Install dictionary service dependencies (independent frozen lockfile)
run: pnpm --dir runtime/services/master-data-registry install --frozen-lockfile
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build runtime modules (fixture suites evaluate migrated rules from dist)
run: pnpm runtime:build:modules
- name: Repo-root governance gate
run: pnpm check
- name: Source tree must stay clean apart from latest reports (no tracked .npmrc mutation)
run: |
git status --porcelain | grep -vE '\.latest\.json$' && { echo "::error::静态门禁修改了报告以外的跟踪文件"; exit 1; } || echo "clean apart from latest reports"
- if: always()
name: Upload static evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-static-${{ env.CANDIDATE_TAG }}
path: |
reports/*.latest.json
runtime/reports/*.latest.json
!runtime/reports/runtime-acceptance.latest.json
!runtime/reports/ui-acceptance.latest.json
retention-days: "30"
timeout-minutes: "30"
permissions:
contents: read
...
|
static
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|
|
46096
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
Unit tests without DB (modules / packages / govern Unit tests without DB (modules / packages / governance)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
unit:
name: Unit tests without DB (modules / packages / governance)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Generate clients for authority module unit imports (no database)
run: pnpm --dir runtime prisma:generate
- name: Module / package unit tests
run: pnpm --dir runtime exec turbo run test --filter='./modules/*' --filter='./packages/*' --filter='./clients/*' --force
- name: Governance package tests
run: pnpm governance:test
timeout-minutes: "20"
permissions:
contents: read
...
|
unit
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|
|
46097
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
Port conformance (kernel / modules / clients)
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
port-conformance:
name: Port conformance (kernel / modules / clients)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Run port conformance with complete suite coverage
run: pnpm check:port-conformance
- if: always()
name: Upload port conformance evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: error
name: platform-port-conformance-${{ env.CANDIDATE_TAG }}
path: reports/port-conformance.latest.json
retention-days: "30"
timeout-minutes: "20"
permissions:
contents: read
...
|
port-conformance
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|
|
46098
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
Runtime and UI acceptance (real PostgreSQL + Redis Runtime and UI acceptance (real PostgreSQL + Redis)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
runtime:
name: Runtime and UI acceptance (real PostgreSQL + Redis)
runs-on: ubuntu-latest
env:
# 库名前缀由 runtime/package.json name 派生(G15 基座守卫:enterprise_platform*)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_platform_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379
KAFKA_BROKERS: 127.0.0.1:59092
MAINLINE_CHAOS_CONTAINER: enterprise-platform-ms23-ci-redpanda-1
# Compose parses all services even for --no-deps redpanda and down.
# These unused service values deliberately cannot start a runtime.
PLATFORM_DEPLOYMENT_ENV: test
PLATFORM_RUNTIME_IMAGE: enterprise-platform/runtime:ci-not-started
PLATFORM_RUNTIME_DATABASE_RUNTIME_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_DATABASE_SYSTEM_URL: postgresql://unused@127.0.0.1:1/unused
PLATFORM_RUNTIME_REDIS_URL: redis://127.0.0.1:1/15
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: runtime/pnpm-lock.yaml
node-version: "22"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install runtime workspace (frozen lockfile)
run: pnpm --dir runtime install --frozen-lockfile
- name: Install Playwright browser
run: pnpm --dir runtime --filter web exec playwright install --with-deps chromium
- name: Workbench browser regressions (intercepted read APIs)
run: pnpm check:workbench-ui
- name: Generate Prisma clients
run: pnpm --dir runtime prisma:generate
- name: Build persistence modules and provision every module acceptance database
run: |
pnpm runtime:build:modules
node governance/prepare-module-databases.mjs
- name: Prepare mainline fixtures and verify identity ordinary-role databases
run: |
pnpm mainline:prepare
pnpm identity:prepare
- name: Policy activation concurrency and lease fencing (isolated PostgreSQL with RLS)
run: pnpm check:policy-governance
- name: Build isolated MinIO from pinned upstream source
run: docker build -t enterprise-platform/test-minio:a6c538c5 stack/test-minio
- name: Real file and notification execution slices (S3, ClamAV, durable receiver receipts)
run: pnpm check:execution-slices
env:
EXECUTION_CLAMAV_PORT: "3310"
- name: Registry admission and central audit recovery
run: pnpm check:registry-admission
- name: Start isolated Redpanda and provision registered topics
run: |
docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml up -d --wait --no-deps redpanda
bash stack/provision/redpanda-topics.sh --apply
- name: Real DB and Redis acceptance (deploy → RLS roles → differential → tests incl. 7 profile boots)
run: pnpm runtime:check:runtime
- name: Configuration snapshots, tenant isolation and remote SDK acceptance
run: pnpm acceptance:configuration
- name: Persistent mainline, audit tamper, revocation SLA and real broker failure
run: pnpm mainline:check
- name: Identity signing against isolated OpenBao Transit
run: pnpm identity:check:transit
- name: UI acceptance (NestJS / Fastify x WS / SSE)
run: pnpm runtime:check:ui
env:
UI_MATRIX: "1"
- name: Identity module browser acceptance (login / MFA / consent / sessions)
run: pnpm identity:check:module-ui
- name: MCP controlled writes (isolated IdP, Owner receipt, retry and revocation)
run: pnpm check:mcp-writes
- if: always()
name: Upload workbench browser diagnostics
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-workbench-browser-${{ env.CANDIDATE_TAG }}
path: /tmp/platform-workbench-ui-*/
retention-days: "7"
- if: always()
name: Upload runtime and UI evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-runtime-${{ env.CANDIDATE_TAG }}
path: |
runtime/reports/runtime-acceptance.latest.json
runtime/reports/ui-acceptance.latest.json
reports/workbench-ui.latest.json
reports/identity-ui.latest.json
reports/mcp-writes.latest.json
reports/mainline-acceptance.latest.json
reports/configuration-runtime.latest.json
reports/revocation-sla.latest.json
reports/policy-governance.latest.json
reports/execution-slices.latest.json
reports/registry-admission.latest.json
reports/identity-transit.latest.json
reports/scope-http.latest.json
reports/scope-fact-sla.latest.json
reports/machine-revocation-sla.latest.json
reports/credential-m1-sla.latest.json
retention-days: "30"
- if: always()
name: Stop isolated acceptance broker
run: docker compose -p enterprise-platform-ms23-ci -f stack/compose.yaml -f stack/overlays/test.yaml down
timeout-minutes: "50"
services:
clamav:
image: clamav/clamav-debian@sha256:be3cb41d9833ce9ffb98f3d3e1483c35c0d87060c2bda3624d75fd28bbf0b3bd
ports:
- 3310:3310
options: --health-cmd "clamdcheck.sh" --health-start-period 120s --health-interval 10s --health-timeout 5s --health-retries 24
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_platform_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_platform_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
runtime
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|
|
46099
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
M1 identity transitional workspace (IdP static → E M1 identity transitional workspace (IdP static → E2 → governance)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
identity:
name: M1 identity transitional workspace (IdP static → E2 → governance)
runs-on: ubuntu-latest
env:
# 库名前缀由 identity/package.json name 派生(enterprise_idp*);Redis 必须 db 0(老框架 C22)
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/enterprise_idp_ci?schema=public
REDIS_URL: redis://127.0.0.1:6379/0
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: identity/pnpm-lock.yaml
node-version: "20"
- name: Private registry auth (temporary userconfig; shared runtime identity fixture dependencies)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Install identity workspace (frozen lockfile)
run: pnpm --dir identity install --frozen-lockfile
- name: Build shared identity fixture dependencies from this checkout
run: |
pnpm --dir runtime install --frozen-lockfile --filter @juhai/module-identity... --filter @juhai/client-identity --filter api-nestjs
pnpm --dir runtime --filter @juhai/module-identity prisma:generate
pnpm --dir runtime exec turbo run build --filter=@juhai/module-identity... --filter=@juhai/client-identity...
pnpm --dir identity --filter api-nestjs exec node -e "require('node:assert/strict').strictEqual(require('@juhai/module-kit'), require('../../../runtime/modules/kit'))"
- name: Provision ordinary owner for the isolated identity test database
run: |
psql "${DATABASE_URL%%\?*}" -v ON_ERROR_STOP=1 <<'SQL'
CREATE ROLE enterprise_idp_ci_rt LOGIN PASSWORD 'ci-test-only' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;
ALTER DATABASE enterprise_idp_ci OWNER TO enterprise_idp_ci_rt;
ALTER SCHEMA public OWNER TO enterprise_idp_ci_rt;
SQL
echo 'DATABASE_URL=postgresql://enterprise_idp_ci_rt:ci-test-only@127.0.0.1:5432/enterprise_idp_ci?schema=public' >> "$GITHUB_ENV"
- name: Generate Prisma clients
run: pnpm --dir identity prisma:generate
- name: IdP static sub-checks (independent of runtime / UI reports)
run: pnpm identity:check:static
- name: IdP real DB acceptance (single NestJS host, serialized)
run: pnpm identity:check:runtime
- name: Install Playwright browser
run: pnpm --dir identity --filter web exec playwright install --with-deps chromium
- name: IdP UI acceptance (single NestJS host)
run: pnpm identity:check:ui
- name: IdP final governance aggregation (same checkout, fresh runtime / UI reports)
run: pnpm identity:check:governance
- if: always()
name: Upload identity evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-identity-${{ env.CANDIDATE_TAG }}
path: identity/reports/*.latest.json
retention-days: "30"
timeout-minutes: "50"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: enterprise_idp_ci
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d enterprise_idp_ci" --health-interval 5s --health-timeout 5s --health-retries 20
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 20
permissions:
contents: read
...
|
identity
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|
|
46100
|
26780
|
116
|
5
|
6eab1cffee8143f5fc616c05f65a6d827159eaad
|
0
|
Runtime image build + SBOM (+ cosign when a key is Runtime image build + SBOM (+ cosign when a key is provided)...
|
0
|
name: Platform
"on":
pull_request:
name: Platform
"on":
pull_request:
push:
branches: [main]
workflow_dispatch:
env:
GITEA_ACTIONS: "true"
PNPM_VERSION: 9.15.9
jobs:
image:
name: Runtime image build + SBOM (+ cosign when a key is provided)
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Candidate tag (real run attempt, computed per job)
run: |
if ! [[ "${GITHUB_RUN_ATTEMPT:-}" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::GITHUB_RUN_ATTEMPT is missing or invalid on this runner; the candidate tag needs the real attempt (no fallback, decision 2026-10-11)"
exit 1
fi
echo "CANDIDATE_TAG=${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_ENV"
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: "0"
- name: Enable pnpm
run: |
corepack enable
corepack prepare pnpm@${PNPM_VERSION} --activate
- uses: https://github.com/actions/setup-node@v4
with:
node-version: "20"
- name: Private registry auth (temporary userconfig)
uses: ./.github/actions/private-npm
with:
token: ${{ secrets.PLATFORM_NPM_TOKEN }}
- name: Install locked governance tools
run: pnpm --dir governance install --frozen-lockfile --ignore-scripts
- name: Resolve npmrc for BuildKit secret (never printed)
run: |
cfg="${RUNNER_TEMP}/platform-npmrc-resolved"
umask 077
printf '@juhai:registry=https://gitea.g-hi.com/api/packages/luoanwu/npm/\n//gitea.g-hi.com/api/packages/luoanwu/npm/:_authToken=%s\n' "${GITEA_NPM_TOKEN}" > "${cfg}"
echo "PLATFORM_NPMRC=${cfg}" >> "${GITHUB_ENV}"
- name: Build runtime image from git archive HEAD:runtime (reports/image-digest.json)
run: node governance/build-image.mjs --context head --npmrc "${PLATFORM_NPMRC}"
- name: Install syft (pinned) and generate SPDX SBOM
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${RUNNER_TEMP}/bin" v1.20.0
PATH="${RUNNER_TEMP}/bin:${PATH}" node governance/sbom.mjs
- name: Install cosign (pinned)
uses: https://github.com/sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign image when COSIGN_PRIVATE_KEY is provided (otherwise explicit skip)
run: |
if [ -n "${COSIGN_PRIVATE_KEY}" ]; then
umask 077; printf '%s' "${COSIGN_PRIVATE_KEY}" > "${RUNNER_TEMP}/cosign.key"
COSIGN_KEY="${RUNNER_TEMP}/cosign.key" node governance/sign-image.mjs
else
node governance/sign-image.mjs
fi
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- if: always()
name: Upload image evidence
uses: https://github.com/actions/upload-artifact@v3
with:
if-no-files-found: warn
name: platform-image-${{ env.CANDIDATE_TAG }}
path: |
reports/image-digest.json
reports/sbom.spdx.json
reports/sbom.latest.json
reports/signature.json
retention-days: "30"
timeout-minutes: "40"
permissions:
contents: read
...
|
image
|
["static"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1793525602
|
1793525382
|
1793525602
|
|
0
|
|
0
|
Edit
Delete
|