Skip to content

Skill: no-portal setup and native app attestation (export of CLI#101; merge after CLI 0.3.0) - #8

Closed
kivtxs wants to merge 3 commits into
mainfrom
export/cli-agent-project-setup
Closed

kivtxs wants to merge 3 commits into
mainfrom
export/cli-agent-project-setup

Conversation

@kivtxs

@kivtxs kivtxs commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

What

Export of Offline-Protocol/CLI@4076fc4 (branch feat/agent-project-setup, CLI#101) with scripts/export-agent-plugins.mjs: the plugin skill build-with-offline-protocol gains a section on setting up the developer's application without the portal (local MCP account tools app_status, detect_native_apps, register_native_app, remove_native_app, set_development_builds, set_allowed_origins, set_features, apply_project_setup, and the matching offline apps … / offline apply commands) and on native app attestation (register every iOS/Android app, pass attestation providers, @offline-protocol/id-react-native 0.4.0+, never send an Origin header from a native app).

Why

A coding agent got stuck on Offline ID sign-in in an Expo app because these steps were portal-only and undocumented for agents. Post-mortem: api-gateway docs/postmortems/2026-11-04-native-code-requests.md.

How tested

node scripts/export-agent-plugins.mjs --check against this branch: identical to a fresh export of the CLI branch.

Merge order

Draft on purpose. The launcher here still pins @offline-protocol/cli@0.2.9, which does not have the account tools this text names. Merge after: CLI#101 merged → CLI 0.3.0 released → the pin PR exported (that export will contain this change too, so this PR can simply be closed in favour of it).

Rollout (the whole change set, in order)

Shipped apps must never break, so the servers go first, then the SDK, CLI and MCP, then the portal and docs:

# PR Deploys Env (names only) Notes
0 org setting n/a org secret E2E_CHECKOUT_TOKEN (read-only Contents on api-gateway, developer-service-api, auth-service, CLI) api-gateway → Settings → Actions → General → Access: "Accessible from repositories in the organization", so other repos can call the journey workflow
1 developer-service-api (this lookup) Railway on merge none additive field; older gateways ignore it
2 auth-service (code requests, errors, Expo Android challenge) Railway on merge optional UNATTESTED_CODE_REQUESTS_PER_APP_PER_HOUR (default 300). ATTESTATION_TEST_ANDROID_ROOTS_FILE must stay unset in production (the service refuses to start with it there) deploy before the gateway, so a code_request always meets the per-app cap
3 api-gateway (attestation passthrough, code_request, actionable refusals, journey workflow, CI) Railway on merge none new (APP_AUTH_MODE=enforce stays) from here, an email code from a registered native app works on every SDK version
4 CLI (offline apps native/origins/features/status, offline apply, login --code, MCP account tools) release PR → tag → npm; hosted MCP redeploys on merge none then export to offline-protocol-agent-plugins
5 id-react-native 0.4.0, id-react 0.3.0 npm publish none Android via @expo/app-integrity needs step 2 deployed
6 developer-portal #79, docs #46 Railway / Mintlify none they reference the CLI 0.3.0 commands and SDK 0.4.0

Rollback: revert the deploy of the service in question (no migrations, no data changes). Reverting the gateway restores today's behaviour (native code requests without a credential refused).

Production smoke test (after step 3, no email or text message to anyone)

offline apps create "smoke $(date +%F)" --json      # a throwaway app: not on any bypass list
APP=<its id>
# 1. Nothing registered: refused, and told what to run
curl -s -X POST https://api.offlineprotocol.com/api/v1/auth/send-code -H "x-app-id: $APP" -H 'content-type: application/json' -d '{"email":"not-an-email"}'
#    → 401 app_credentials_required, data.missing = native_registration, data.next_steps has `offline apps native add …`
offline apps native add ios --bundle-id com.example.smoke --team-id ABCDE12345 --app-id $APP
sleep 65                                               # gateway and auth-service cache app settings for 60 s
# 2. Registered, no attestation: admitted (code_request); the invalid address stops it before any email
curl -s … -d '{"email":"not-an-email"}'                # → 400 "A valid email is required" (not 401)
# 3. Text message without attestation: refused before any SMS
curl -s -X POST …/auth/phone/send-code -H "x-app-id: $APP" -d '{"phone":"+1"}'   # → 401, data.missing = attestation
# 4. Sign-in without attestation: refused
curl -s -X POST …/auth/verify-code -H "x-app-id: $APP" -d '{"email":"not-an-email","otp":"000000"}'   # → 401, data.missing = attestation
offline apps native remove ios --bundle-id com.example.smoke --app-id $APP   # then delete the app in the portal or leave it unused

An attested sign-in needs a real device (the test device's root is never trusted in production); test it from a release build after step 5.

…): skill covers the no-portal setup and native app attestation

Draft: merge only after CLI#101 is merged and the CLI 0.3.0 pin is exported;
the pinned 0.2.9 launcher does not have the account tools this text names.
…velopment mode, Android policy, hosted app_status
@kivtxs

kivtxs commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

Round 2 of this change set (development mode, degraded Android phones, real-device chain checks, hosted MCP status) is on developer-service-api#85, auth-service#35, api-gateway#23 and CLI#101. Updated merge and deploy order for all PRs:

# PR Deploys Env (names only) Notes
0 org setting n/a org secret E2E_CHECKOUT_TOKEN (read-only Contents on api-gateway, developer-service-api, auth-service, CLI) api-gateway → Settings → Actions → General → Access: "Accessible from repositories in the organization"; make "Third-party developer journey" a required check on the four repos and id-sdk-react-native
1 developer-service-api #85 Railway on merge; migration 047 (new table application_attestation_events, additive) runs on start none new fields are additive; older gateways and auth-services ignore them
2 auth-service #35 Railway on merge optional: UNATTESTED_CODE_REQUESTS_PER_APP_PER_HOUR (300), DEVELOPMENT_SIGN_INS_PER_APP_PER_HOUR (200), DEGRADED_SIGN_INS_PER_APP_PER_HOUR (500), DEGRADED_SIGN_INS_PER_CLIENT_PER_HOUR (30). ATTESTATION_TEST_ANDROID_ROOTS_FILE must stay unset (the service refuses to start with it in production) from this deploy, Android phones that cannot fully attest sign in as app_trust: "degraded" (capped) instead of being refused, and real factory-keybox chains verify; tokens gain app_trust
3 api-gateway #23 Railway on merge none new (APP_AUTH_MODE=enforce stays; ATTESTATION_BYPASS_APP_IDS unchanged) from here: email codes from registered native apps on any SDK, development mode, attestation passed through on code requests, actionable refusals
4 CLI #101 merge auto-deploys the hosted MCP (app_status on /mcp); then the release PR → tag → npm 0.3.0; then the plugin export (offline-protocol-agent-plugins #8 is superseded by that export) hosted MCP: PUBLIC_SETUP_TOOLS_ENABLED stays unset until the team chooses to list the setup tools on /public/mcp the registry pin moves to id-react-native 0.4.0 once it is on npm
5 id-sdk-core #2 (with/after Aditi's #1), id-sdk-react-native #15 (0.4.0), id-sdk-react #25 (0.3.0) npm publish (id-react-native's release waits for the journey check) none Expo Android attestation needs step 2 deployed
6 developer-portal #79, docs #46 Railway / Mintlify none reference CLI 0.3.0 and SDK 0.4.0

Rollback: revert the service's deploy. Migration 047 only adds a table; nothing else changes data. Reverting auth-service restores refusals for degraded devices; reverting the gateway restores today's 401 for native code requests.

@kivtxs

kivtxs commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

Superseded by #9, the export of CLI 0.3.1 (CLI#102 release, CLI#103 pins). It contains this change (no-portal app setup and native attestation in the skill) plus the 0.3.1 pins, the id-react 0.3.0 / id-react-native 0.4.0 guidance and the refused-chain wording. Merge #9 after 0.3.1 is on npm.

@kivtxs kivtxs closed this Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant