Skip to content

docs(deploy-to-cloud-engine): pin the II derivation origin at first deploy - #340

Merged
marc0olo merged 2 commits into
mainfrom
docs/engine-derivation-origin
Aug 12, 2026
Merged

docs(deploy-to-cloud-engine): pin the II derivation origin at first deploy#340
marc0olo merged 2 commits into
mainfrom
docs/engine-derivation-origin

Conversation

@yhabib

@yhabib yhabib commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Motivation

The engine console now shows an app's canister address and names it as the origin an Internet Identity app should derive from (dfinity/control-panel#3394, dfinity/control-panel#3398). The console can only tell the user — the canisters are the user's to write, so the agent deploying them is the one that has to act. And it cannot be fixed later: a domain that has already collected sign-ins cannot be repointed at a derivation origin without orphaning every account made under it.

Changes

  • Added a subsection to Step 2 saying to pin the derivation origin on the first deploy, before the app has users.
  • Pointed at the canister that serves the frontend as the one whose address to use, built from its canister id.
  • Called out that __META_BASE_URL is not the answer. It is allowed to hold a custom domain, and a custom domain is the one value that must never become the derivation origin.
  • Demoted __META_MAIN_CANISTER to the usual case rather than the rule. It is a console display flag and does not promise the canister serves HTTP.
  • Noted the Caffeine exception: Caffeine owns those apps' addresses, so the address is not the app's to derive from.
  • Added Pitfall 18 and one eval case. Left the mechanics in internet-identity and linked to it.
Eval 17 — Adversarial: II derivation origin when __META_BASE_URL is a custom domain (WITH 3/3 | WITHOUT 1/3)
━━━ Adversarial: II derivation origin when __META_BASE_URL is a custom domain ━━━

  WITH skill: 3/3 passed
    ✅ Gives the frontend canister address https://abcde-aaaaa-aaaaa-aaaaa-cai.icp.net as the derivation origin
    ✅ Explicitly does NOT use the custom domain https://app.example.com as the derivation origin, even though __META_BASE_URL is set to it
    ✅ Says to set it on the first deploy, before the app has users, because it cannot be applied retroactively without orphaning existing accounts

  WITHOUT skill: 1/3 passed
    ❌ Gives the frontend canister address https://abcde-aaaaa-aaaaa-aaaaa-cai.icp.net as the derivation origin
       → The output gives https://abcde-aaaaa-aaaaa-aaaaa-cai.icp0.io instead of the expected icp.net domain.
    ✅ Explicitly does NOT use the custom domain https://app.example.com as the derivation origin, even though __META_BASE_URL is set to it
    ❌ Says to set it on the first deploy, before the app has users, because it cannot be applied retroactively without orphaning existing accounts
       → The output only warns that login fails if the alternative-origins file is missing, but never states that derivationOrigin must be set before any users exist or that changing it later orphans existing accounts.

The case does not isolate the __META_BASE_URL correction. I ran it against the pre-fix text and that scores 3/3 too, because the rest of the section says the canister address "survives adding, changing, or dropping a custom domain", so an agent reads past the bad clause instead of following it literally. Treat this as a regression guard for the corrected guidance, not as evidence for the correction. The correction stands on the text having been self-contradictory.

I dropped a fourth behavior I had drafted ("lists the custom domain as an alternative origin") because it tests the .well-known mechanics this skill deliberately delegates to internet-identity.


Prev. #339

…eploy

The engine console now names an app's canister address as the origin an
Internet Identity app should derive from (dfinity/control-panel#3394,
#3398). Canisters are the user's to write, so the agent deploying them is
the one that has to get this right, and it is not recoverable later: a
domain that has already collected sign-ins cannot be repointed at a
derivation origin without orphaning every account made under it.

The engine-specific part is which URL to use. The console derives the
address from the canister marked __META_MAIN_CANISTER: "true" — the same
canister whose __META_BASE_URL Step 2 already sets — so the value the
agent needs is one it has computed by that point.

Mechanics (derivationOrigin, .well-known/ii-alternative-origins, the
_headers entry the static-site recipe needs) stay in internet-identity;
this only points there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yhabib
yhabib requested review from a team and JoshDFN as code owners August 7, 2026 16:53
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Skill Validation Report

Validating skill: /home/runner/work/icskills/icskills/skills/deploy-to-cloud-engine

Structure

  • Pass: SKILL.md found

Frontmatter

  • Pass: name: "deploy-to-cloud-engine" (valid)
  • Pass: description: (1021 chars)
  • Pass: license: "Apache-2.0"
  • Pass: compatibility: (211 chars)
  • Pass: metadata: (2 entries)

Tokens

  • Warning: SKILL.md body is 8383 tokens (spec recommends < 5000)

Markdown

  • Pass: no unclosed code fences found

Tokens

File Tokens
SKILL.md body 8,383
Total 8,383

Content Analysis

Metric Value
Word count 5,448
Code block ratio 0.09
Imperative ratio 0.13
Information density 0.11
Instruction specificity 0.94
Sections 19
List items 90
Code blocks 17

Contamination Analysis

Metric Value
Contamination level low
Contamination score 0.09
Primary language category shell
Scope breadth 3
  • Warning: Language mismatch: config (1 category differ from primary)

Result: 1 warning

Project Checks


✓ Project checks passed for 1 skills (0 warnings)

marc0olo added a commit that referenced this pull request Aug 10, 2026
… origin (#339)

# Motivation

The skill only mentioned `derivationOrigin` and `ii-alternative-origins`
in Pitfall 8, to say don't use them. That is right for the `icp0.io` vs
`ic0.app` case it covers, but it was the whole coverage, so an agent
adding a custom domain to an II app found a prohibition and no recipe.
`custom-domains` Pitfall 9 already pointed here for one. The engine
console started surfacing this in dfinity/control-panel#3394 and
dfinity/control-panel#3398.

# Changes

- Added a "Serving an app at more than one origin" section: pick the
canister address as the derivation origin, set `derivationOrigin` on the
alternative origin only, and serve `.well-known/ii-alternative-origins`
from the derivation origin's canister.
- Added the `_headers` block the `@dfinity/static-site` recipe needs.
The [official
docs](https://docs.internetcomputer.org/building-apps/authentication/alternative-origins)
say to use `.ic-assets.json5`, which is the legacy asset canister's
config — static-site does not read or upload it. The file also has no
extension, so it will not serve as `application/json` without a
`_headers` entry, and certified-assets sets no CORS header by default.
- Scoped Pitfall 8 to the `icp0.io`/`ic0.app` case and pointed it at the
new section.
- Added one eval case. Dropped a second one I drafted ("which origin
gets `derivationOrigin`") because the baseline scored 3/3 on it — it
tested common knowledge, not the skill.

<details>
<summary>Eval 14 — Adversarial: alternative origins on the static-site
recipe (WITH 3/3 | WITHOUT 2/3)</summary>

```
━━━ Adversarial: alternative origins on the static-site recipe ━━━

  WITH skill: 3/3 passed
    ✅ Serves .well-known/ii-alternative-origins containing {"alternativeOrigins": [...]}
    ✅ Adds a _headers entry setting Content-Type: application/json AND Access-Control-Allow-Origin: * for /.well-known/ii-alternative-origins
    ✅ Does NOT create a .ic-assets.json5 file

  WITHOUT skill: 2/3 passed
    ✅ Serves .well-known/ii-alternative-origins containing {"alternativeOrigins": [...]}
    ❌ Adds a _headers entry setting Content-Type: application/json AND Access-Control-Allow-Origin: * for /.well-known/ii-alternative-origins
       → No _headers file or entry is included anywhere in the output.
    ✅ Does NOT create a .ic-assets.json5 file
```

The baseline writes the JSON file and stops, which leaves it served with
the wrong content type and no CORS header.

</details>

---

Next #340, #341

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Marco Walz <marco.walz@dfinity.org>
@marc0olo

marc0olo commented Aug 10, 2026

Copy link
Copy Markdown
Member

Both the new subsection and Pitfall 18 call the derivation origin "the same [value/URL] as __META_BASE_URL". But __META_BASE_URL can be a custom domain (skill lines 151 and 219: "you can set it up front"), while the derivation origin must stay the canister address — which is exactly why the console derives it from the canister id, not the base URL:

Unlike defaultDomain it never moves to a custom domain, which is what makes it the address an Internet Identity app should derive from.

So when __META_BASE_URL is a custom domain, "same as __META_BASE_URL" aims derivationOrigin at the custom domain — the mistake this PR is meant to prevent.

Suggest dropping the equivalence: it is the main canister's canister address https://<main-canister-id>.icp.net, which matches __META_BASE_URL only while that has not been pointed at a custom domain. The eval's behavior #2 ("notes it is the same URL as __META_BASE_URL") carries the same conflation and would need the same softening.

…ntend canister

Review feedback on #340. Both the subsection and Pitfall 18 called the
derivation origin "the same value as __META_BASE_URL". That variable is
allowed to hold a custom domain (lines 151 and 219 say so), and a custom
domain is exactly what must never become the derivation origin. The two
values agree only at first deploy and diverge in the case the guidance
exists for.

Also drops __META_MAIN_CANISTER as the anchor. That flag is a console
display setting and does not promise the canister serves HTTP. A backend
canister cannot be a derivation origin: the browser is never on it, and
it cannot serve the .well-known/ii-alternative-origins file II fetches
from that origin. The rule now points at the canister that serves the
frontend, with the flag demoted to the usual case.

Eval 17 carried the same conflation in behavior #2 and is rewritten
around a setup where __META_BASE_URL is a custom domain. Note the case
does not isolate this fix: the old text also passes it, because the rest
of the section contradicts the bad clause.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yhabib

yhabib commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Good catch, you're right. Fixed in 6a8f4e3.

__META_BASE_URL and the derivation origin agree only at first deploy, and they diverge in exactly the case the guidance is written for. Dropped the equivalence and turned it into an explicit warning, since a reader who has already pointed __META_BASE_URL at a domain is the one most likely to make the inference I did.

I also dropped __META_MAIN_CANISTER as the anchor while I was in there. It is a console display flag and does not promise the canister serves HTTP. If someone marks a backend canister, the old wording sent them to an origin the browser is never on and which cannot serve the .well-known/ii-alternative-origins file II fetches to validate the claim. The rule now points at the canister that serves the frontend, with the flag as the usual case and __META_BASE_URL called out as never the answer.

One thing worth flagging, since it cuts against the fix. I rewrote eval 17 around a setup where __META_BASE_URL is a custom domain, then ran it against the old text to confirm it catches the bug. It does not: the old text also scores 3/3. The rest of the section says the canister address "survives adding, changing, or dropping a custom domain", so an agent reads past the bad clause rather than following it literally.

So the practical blast radius was smaller than my PR description implied, and the eval is a regression guard for the corrected guidance rather than proof of this fix. The text was still self-contradictory and worth correcting on its own. Current numbers are WITH 3/3 | WITHOUT 1/3, with the delta on the icp.net domain and the before-you-have-users timing.

I dropped a fourth behavior I had drafted ("lists the custom domain as an alternative origin") because it tests the .well-known mechanics this skill deliberately delegates to internet-identity.

@marc0olo
marc0olo merged commit f767214 into main Aug 12, 2026
6 checks passed
@marc0olo
marc0olo deleted the docs/engine-derivation-origin branch August 12, 2026 09:08
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.

2 participants