Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/t3safe-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Done when the branch has the merge, all conflicts resolved, and the old review a

For each new or changed outbound call, record its trigger (startup/timer/render/provider probe or explicit user action), agent reachability (MCP/shell/preview), shipped surfaces (desktop/server/CLI/web/mobile), destination and payload. Inspect these boundaries every sync:

- Self-update and distribution sources: `releases`, `api.github.com/repos`, `raw.githubusercontent.com`, `registry.npmjs.org`, `SHA256SUMS`, `install.sh`; settings newly defaulting to true that cause networking.
- Self-update and distribution sources: preserve the safe-only GitHub updater, forced latest channel, certificate-pinned designated requirement, committed public fingerprint, protected `release` signing job, secret-free PR build, and ZIP/blockmap/latest-mac.yml assets. Never regenerate or replace the stable signing key during a sync. `releases`, `api.github.com/repos`, `raw.githubusercontent.com`, `registry.npmjs.org`, `SHA256SUMS`, `install.sh`; settings newly defaulting to true that cause networking.
- Renderer resources: `<img>`, `<video>`, `<iframe>`, CSS URLs/imports, CSP and Electron permission handlers; clipboard/geolocation must retain explicit authorization.
- Child-process environments, provider SDK initialization and dependency-owned endpoints. Inspect the relevant locked package `dist` URLs without executing it.
- Every `HttpClient` acquisition in server cloud, relay and telemetry code still uses `enforceManagedCapability` or a gated constructor.
Expand Down
102 changes: 102 additions & 0 deletions .github/actions/build-safe/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Build safe artifacts
description: Shared secret-free build steps; release job supplies only an imported keychain.
runs:
using: composite
steps:
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "26.12.1"
- name: Verify runner and dependency baseline before install
shell: bash
run: |
test "$(uname -m)" = arm64
node scripts/safe/workflow-scan.ts
node scripts/safe/egress-scan.ts
node scripts/safe/dependency-scan.ts
- uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
with:
node-version: "26.12.1"
run-install: false
cache: false
- shell: bash
run: vp install --frozen-lockfile
- shell: bash
run: |
node scripts/safe/policy-verify.ts
node scripts/safe/stage-lock-scan.ts
- name: Build desktop DMG
shell: bash
run: |
node scripts/build-desktop-artifact.ts --platform mac --target dmg --arch arm64 \
--build-version "$SAFE_VERSION" --output-dir release-safe
dmg=(release-safe/*.dmg)
test "${#dmg[@]}" -eq 1
test -f "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.dmg"
- name: Inspect policy and endpoints inside the built DMG
shell: bash
run: |
node scripts/safe/desktop-smoke.ts "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.dmg" --artifact-report release-safe/dmg-host-report.json
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "26.8.2"
- name: Build standalone CLI and resource monitor
env:
# Node single-executable builds need >= 25.7; vp otherwise runs its own pinned Node.
VP_NODE_VERSION: "26.8.2"
shell: bash
run: |
node scripts/update-release-package-versions.ts "$SAFE_VERSION"
node apps/server/scripts/cli.ts build-exe --target darwin-arm64 --verbose
# Preserve the exact SEA input under stable scanner-relative paths, without runner metadata.
mkdir "$RUNNER_TEMP/cli-build"
cp apps/server/dist-exe/bin.mjs "$RUNNER_TEMP/cli-build/bin.mjs"
cp -R apps/server/dist/client "$RUNNER_TEMP/cli-build/client"
cargo build --locked --release --target aarch64-apple-darwin --manifest-path native/resource-monitor/Cargo.toml
mkdir -p "$RUNNER_TEMP/cli-resource-monitor/darwin-arm64"
cp native/resource-monitor/target/aarch64-apple-darwin/release/t3-resource-monitor "$RUNNER_TEMP/cli-resource-monitor/darwin-arm64/"
node scripts/build-cli-archive.ts --platform mac --arch arm64 --version "$SAFE_VERSION" \
--resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" --output-dir release-safe
mv "release-safe/t3-${SAFE_VERSION}-darwin-arm64.tar.gz" "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.tar.gz"
- name: Verify baked CLI policy without a listener or provider processes
shell: bash
run: |
mkdir "$RUNNER_TEMP/safe-smoke"
tar -xzf "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.tar.gz" -C "$RUNNER_TEMP/safe-smoke"
executable="$RUNNER_TEMP/safe-smoke/t3-${SAFE_VERSION}-darwin-arm64/t3"
node scripts/safe/egress-smoke.ts "$executable"
status=0
node scripts/safe/policy-verify.ts --cli-bundle "$RUNNER_TEMP/cli-build" || status=1
node scripts/safe/artifact-scan.ts "$RUNNER_TEMP/cli-build" --report release-safe/cli-build-host-report.json || status=1
node scripts/safe/artifact-scan.ts "$RUNNER_TEMP/safe-smoke/t3-${SAFE_VERSION}-darwin-arm64" --report release-safe/cli-archive-host-report.json || status=1
exit "$status"
- if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: t3safe-cli-scan-input
path: ${{ runner.temp }}/cli-build/
if-no-files-found: warn
retention-days: 7
- name: Package management command, policy and checksums
shell: bash
run: |
cp scripts/safe/t3safe release-safe/t3safe
cp security/managed-policy.json release-safe/managed-policy.json
cp security/app-identity.json release-safe/app-identity.json
printf '%s\n' "v$SAFE_VERSION" > release-safe/VERSION
cp install.sh release-safe/install.sh
test -f release-safe/latest-mac.yml
test -n "$(find release-safe -maxdepth 1 -name '*.zip' -print -quit)"
test -n "$(find release-safe -maxdepth 1 -name '*.blockmap' -print -quit)"
if [[ -n "${SAFE_SIGNING_KEYCHAIN:-}" ]]; then
cp "$RUNNER_TEMP/signing-certificate.sha256" release-safe/signing-certificate.sha256
fi
cd release-safe
shasum -a 256 ./*.dmg ./*.zip ./*.blockmap latest-mac.yml ./*.tar.gz t3safe managed-policy.json app-identity.json VERSION install.sh > SHA256SUMS
if [[ -f signing-certificate.sha256 ]]; then shasum -a 256 signing-certificate.sha256 >> SHA256SUMS; fi
- if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: t3safe-release
path: release-safe/
if-no-files-found: error
retention-days: 7
4 changes: 2 additions & 2 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ jobs:
run: |
vp test run scripts/safe/t3safe.test.ts
vp test run scripts/safe/managed-policy.test.ts apps/server/src/telemetry/ManagedGates.test.ts apps/desktop/src/updates/ManagedUpdates.test.ts
vp test run scripts/safe/artifact-scan.test.ts scripts/safe/desktop-smoke-command.test.ts
vp test run scripts/safe/artifact-scan.test.ts scripts/safe/desktop-smoke-command.test.ts scripts/safe/bundle-policy.test.ts scripts/safe/install.test.ts
vp test run scripts/safe/dependency-comparison.test.ts scripts/safe/dependency-registry.test.ts scripts/safe/dependency-scan.test.ts
vp test run apps/mobile/src/features/settings/environment-maintenance.test.ts apps/server/src/cli/thread.test.ts apps/server/src/project/RepositoryIdentityResolver.test.ts apps/server/src/provider/ModelManifest.test.ts packages/provider-muse/src/server/maintenance.test.ts apps/desktop/scripts/electron-runtime-integrity.test.mjs
vp test run scripts/build-npm-launcher.test.ts
vp test run scripts/build-desktop-artifact.test.ts -t "installs production dependencies with the reviewed frozen lockfile"
vp test run scripts/build-desktop-artifact.test.ts -t "installs production dependencies with the reviewed frozen lockfile|pins release feeds"
- name: Install test browser and verify disabled action
run: |
node apps/web/node_modules/playwright/cli.js install --only-shell chromium
Expand Down
37 changes: 32 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ on:
- "tsconfig*.json"
- "vite.config.ts"
- "third-party-licenses.config.json"
- ".github/actions/build-safe/**"
- ".github/workflows/safe-build.yml"
- ".github/workflows/release.yml"
permissions:
Expand Down Expand Up @@ -113,16 +114,39 @@ jobs:
node scripts/safe/stage-lock-scan.ts
build:
needs: plan
if: needs.plan.outputs.release == 'true'
uses: ./.github/workflows/safe-build.yml
with:
version: ${{ needs.plan.outputs.version }}
if: needs.plan.outputs.release == 'true' && github.ref == 'refs/heads/main'
runs-on: macos-15
environment: release
timeout-minutes: 60
permissions:
contents: read
env:
SAFE_VERSION: ${{ needs.plan.outputs.version }}
CSC_IDENTITY_AUTO_DISCOVERY: "false"
T3CODE_TELEMETRY_ENABLED: "false"
T3CODE_DISABLE_AUTO_UPDATE: "false"
T3CODE_MOBILE_UPDATES_ENABLED: "0"
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: ${{ needs.plan.outputs.commit }}
persist-credentials: false
- name: Import the stable release identity into an ephemeral keychain
env:
SAFE_SIGNING_P12_BASE64: ${{ secrets.SAFE_SIGNING_P12_BASE64 }}
SAFE_SIGNING_P12_PASSWORD: ${{ secrets.SAFE_SIGNING_P12_PASSWORD }}
run: bash scripts/safe/import-signing-key.sh
- uses: ./.github/actions/build-safe
- name: Delete release signing material
if: always()
run: |
security delete-keychain "$RUNNER_TEMP/t3safe-signing.keychain-db" || true
rm -f "$RUNNER_TEMP/t3safe-signing.p12" "$RUNNER_TEMP/t3safe-signing.pem"
publish:
needs: [plan, build]
if: needs.plan.outputs.release == 'true'
runs-on: macos-15
environment: release
timeout-minutes: 10
permissions:
contents: write
Expand All @@ -146,6 +170,9 @@ jobs:
with:
subject-path: |
release-safe/*.dmg
release-safe/*.zip
release-safe/*.blockmap
release-safe/latest-mac.yml
release-safe/*.tar.gz
release-safe/install.sh
- name: Publish public release assets
Expand All @@ -160,4 +187,4 @@ jobs:
shasum -a 256 --check SHA256SUMS
gh release create "$RELEASE_TAG" ./* --repo "$GITHUB_REPOSITORY" \
--target "$RELEASE_COMMIT" --latest --title "T3 Code $RELEASE_TAG" \
--notes 'Managed macOS Apple Silicon build. Unsigned/ad-hoc signed. See docs/safe-fork/INSTALL.md for installation and policy limits.'
--notes 'Managed macOS Apple Silicon build. Signed with the stable self-signed safe-fork identity; not Apple notarized. See docs/safe-fork/INSTALL.md for installation and policy limits.'
86 changes: 2 additions & 84 deletions .github/workflows/safe-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,92 +15,10 @@ jobs:
SAFE_VERSION: ${{ inputs.version }}
CSC_IDENTITY_AUTO_DISCOVERY: "false"
T3CODE_TELEMETRY_ENABLED: "false"
T3CODE_DISABLE_AUTO_UPDATE: "true"
T3CODE_DISABLE_AUTO_UPDATE: "false"
T3CODE_MOBILE_UPDATES_ENABLED: "0"
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "26.12.1"
- name: Verify runner and dependency baseline before install
run: |
test "$(uname -m)" = arm64
node scripts/safe/workflow-scan.ts
node scripts/safe/egress-scan.ts
node scripts/safe/dependency-scan.ts
- uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
with:
node-version: "26.12.1"
run-install: false
cache: false
- run: vp install --frozen-lockfile
- run: |
node scripts/safe/policy-verify.ts
node scripts/safe/stage-lock-scan.ts
- name: Build desktop DMG
run: |
node scripts/build-desktop-artifact.ts --platform mac --target dmg --arch arm64 \
--build-version "$SAFE_VERSION" --output-dir release-safe
dmg=(release-safe/*.dmg)
test "${#dmg[@]}" -eq 1
mv "${dmg[0]}" "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.dmg"
- name: Inspect policy and endpoints inside the built DMG
run: |
node scripts/safe/desktop-smoke.ts "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.dmg" --artifact-report release-safe/dmg-host-report.json
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "26.8.2"
- name: Build standalone CLI and resource monitor
env:
# Node single-executable builds need >= 25.7; vp otherwise runs its own pinned Node.
VP_NODE_VERSION: "26.8.2"
run: |
node scripts/update-release-package-versions.ts "$SAFE_VERSION"
node apps/server/scripts/cli.ts build-exe --target darwin-arm64 --verbose
# Preserve the exact SEA input under stable scanner-relative paths, without runner metadata.
mkdir "$RUNNER_TEMP/cli-build"
cp apps/server/dist-exe/bin.mjs "$RUNNER_TEMP/cli-build/bin.mjs"
cp -R apps/server/dist/client "$RUNNER_TEMP/cli-build/client"
cargo build --locked --release --target aarch64-apple-darwin --manifest-path native/resource-monitor/Cargo.toml
mkdir -p "$RUNNER_TEMP/cli-resource-monitor/darwin-arm64"
cp native/resource-monitor/target/aarch64-apple-darwin/release/t3-resource-monitor "$RUNNER_TEMP/cli-resource-monitor/darwin-arm64/"
node scripts/build-cli-archive.ts --platform mac --arch arm64 --version "$SAFE_VERSION" \
--resource-monitor-dir "$RUNNER_TEMP/cli-resource-monitor" --output-dir release-safe
mv "release-safe/t3-${SAFE_VERSION}-darwin-arm64.tar.gz" "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.tar.gz"
- name: Verify baked CLI policy without a listener or provider processes
run: |
mkdir "$RUNNER_TEMP/safe-smoke"
tar -xzf "release-safe/t3safe-${SAFE_VERSION}-darwin-arm64.tar.gz" -C "$RUNNER_TEMP/safe-smoke"
executable="$RUNNER_TEMP/safe-smoke/t3-${SAFE_VERSION}-darwin-arm64/t3"
node scripts/safe/egress-smoke.ts "$executable"
status=0
node scripts/safe/policy-verify.ts --cli-bundle "$RUNNER_TEMP/cli-build" || status=1
node scripts/safe/artifact-scan.ts "$RUNNER_TEMP/cli-build" --report release-safe/cli-build-host-report.json || status=1
node scripts/safe/artifact-scan.ts "$RUNNER_TEMP/safe-smoke/t3-${SAFE_VERSION}-darwin-arm64" --report release-safe/cli-archive-host-report.json || status=1
exit "$status"
- if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: t3safe-cli-scan-input
path: ${{ runner.temp }}/cli-build/
if-no-files-found: warn
retention-days: 7
- name: Package management command, policy and checksums
run: |
cp scripts/safe/t3safe release-safe/t3safe
cp security/managed-policy.json release-safe/managed-policy.json
cp security/app-identity.json release-safe/app-identity.json
printf '%s\n' "v$SAFE_VERSION" > release-safe/VERSION
cp install.sh release-safe/install.sh
rm -f release-safe/*.zip release-safe/*.blockmap release-safe/*.yml release-safe/*.yaml
cd release-safe
shasum -a 256 ./*.dmg ./*.tar.gz t3safe managed-policy.json app-identity.json VERSION install.sh > SHA256SUMS
- if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: t3safe-release
path: release-safe/
if-no-files-found: error
retention-days: 7
- uses: ./.github/actions/build-safe
Loading
Loading