@moondeck/station 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +149 -2
- package/bin/uai-host.mjs +130 -0
- package/db/migrations/0000_host_tasks.sql +12 -0
- package/db/migrations/0001_host_ui.sql +11 -0
- package/db/migrations/0002_host_github_tokens.sql +8 -0
- package/db/migrations/0003_host_ssh_keys.sql +8 -0
- package/db/migrations/0004_host_owner_name.sql +1 -0
- package/db/migrations/0005_host_env_vars.sql +5 -0
- package/db/migrations/0006_host_project_env.sql +9 -0
- package/db/migrations/0007_host_github_token_kind.sql +7 -0
- package/db/migrations/0008_host_mcp_connections.sql +18 -0
- package/db/migrations/0009_host_agent_sessions.sql +15 -0
- package/db/migrations/0010_host_engine_accounts.sql +13 -0
- package/db/migrations/0011_codex_thread_id.sql +5 -0
- package/db/migrations/0012_agent_session_attach_key.sql +4 -0
- package/db/migrations/0013_github_credential_generations.sql +11 -0
- package/db/migrations/0014_host_inventory_event_index.sql +1 -0
- package/db/migrations/0015_host_settings.sql +9 -0
- package/db/migrations/0016_task_environment.sql +2 -0
- package/db/migrations/0017_engine_account_scope.sql +7 -0
- package/db/migrations/0018_engine_account_position.sql +3 -0
- package/db/migrations/0019_engine_account_store_ref.sql +3 -0
- package/db/migrations/0020_user_credential_store_ref.sql +6 -0
- package/db/migrations/0021_project_env_store_ref.sql +3 -0
- package/db/migrations/0022_task_project_ids.sql +5 -0
- package/db/migrations/0023_project_env_org.sql +4 -0
- package/db/migrations/0024_task_env_mode.sql +9 -0
- package/db/migrations/0025_project_env_authority.sql +147 -0
- package/db/migrations/0026_project_env_replica.sql +150 -0
- package/db/migrations/0027_cloud_credential_foundation.sql +51 -0
- package/db/migrations/0028_leased_engine_runtimes.sql +11 -0
- package/db/migrations/0029_task_shared_files_mode.sql +5 -0
- package/db/migrations/0030_credential_cleanup_restops.sql +12 -0
- package/db/migrations/meta/_journal.json +223 -0
- package/db/schema.ts +850 -0
- package/images/standard/Dockerfile +347 -0
- package/images/standard/README.md +167 -0
- package/images/standard/container/code-server-settings.json +63 -0
- package/images/standard/container/corepack-version +1 -0
- package/images/standard/container/uai-init +704 -0
- package/images/standard/container/uai-materialize-runtimes +1527 -0
- package/images/standard/container/uai-task-forwarder.mjs +303 -0
- package/images/standard/tool-versions +2 -0
- package/lib/__fixtures__/skill-index/SKILL.md +10 -0
- package/lib/__fixtures__/skill-index/skills/accessibility-checklist.md +7 -0
- package/lib/__fixtures__/skill-index/skills/brand-voice.md +9 -0
- package/lib/__fixtures__/skill-index/skills/design-tokens.md +9 -0
- package/lib/agent-cli.ts +1507 -0
- package/lib/agent-errors.ts +22 -0
- package/lib/agent.ts +672 -0
- package/lib/agents/attach-compatibility.ts +51 -0
- package/lib/agents/claude.ts +918 -0
- package/lib/agents/codex-token-usage.fixture.json +130 -0
- package/lib/agents/codex.ts +1392 -0
- package/lib/agents/cursor-period-usage.ts +253 -0
- package/lib/agents/cursor.ts +562 -0
- package/lib/agents/dispatch.ts +78 -0
- package/lib/agents/durable-proc.ts +334 -0
- package/lib/agents/factory.ts +57 -0
- package/lib/agents/grok.ts +381 -0
- package/lib/agents/kimi.ts +329 -0
- package/lib/agents/machine-durable.ts +604 -0
- package/lib/agents/mock.ts +133 -0
- package/lib/agents/mode.ts +64 -0
- package/lib/agents/opencode.ts +508 -0
- package/lib/agents/output-source.ts +3 -0
- package/lib/agents/proc.ts +221 -0
- package/lib/agents/rate-limit.ts +337 -0
- package/lib/agents/registry.ts +182 -0
- package/lib/agents/session-state.ts +197 -0
- package/lib/agents/skill-index-preamble.fixture.ts +26 -0
- package/lib/agents/transport.ts +741 -0
- package/lib/agents/types.ts +254 -0
- package/lib/agents/uai.ts +106 -0
- package/lib/agents/usage.ts +44 -0
- package/lib/apple-one-off.ts +277 -0
- package/lib/apple-runtime-recycle.ts +237 -0
- package/lib/apple-uninstall-teardown.ts +224 -0
- package/lib/assignment-evidence.ts +94 -0
- package/lib/attachments.ts +48 -0
- package/lib/browser-testing.ts +1537 -0
- package/lib/capture-flow.ts +332 -0
- package/lib/cloud-credential-cleanup-adapter.ts +123 -0
- package/lib/cloud-credential-host.ts +512 -0
- package/lib/cloud-credential-leases.ts +2587 -0
- package/lib/cloud-credential-runtime.ts +1357 -0
- package/lib/cloud-state.ts +56 -0
- package/lib/codex-auth.ts +456 -0
- package/lib/command-db.ts +310 -0
- package/lib/compose-network-recovery.ts +283 -0
- package/lib/connection-secret-redaction.ts +25 -0
- package/lib/container-runtime.ts +1453 -0
- package/lib/credential-cleanup-inventory.ts +490 -0
- package/lib/credential-consumers/engine-anchor.ts +1880 -0
- package/lib/credential-consumers/engines.ts +797 -0
- package/lib/credential-consumers/files.ts +934 -0
- package/lib/credential-consumers/github.ts +702 -0
- package/lib/credential-consumers/mcp.ts +389 -0
- package/lib/credential-consumers/task-files.ts +127 -0
- package/lib/credential-consumers/task-secrets.ts +10 -0
- package/lib/credential-store-pickup.ts +149 -0
- package/lib/credential-store-scope.ts +112 -0
- package/lib/credential-store.ts +932 -0
- package/lib/credentials-activation-authority.ts +709 -0
- package/lib/credentials-purge.ts +1006 -0
- package/lib/custom-connection-capture.ts +395 -0
- package/lib/custom-connection-launch.ts +384 -0
- package/lib/custom-connection-runtime.ts +141 -0
- package/lib/db.ts +80 -0
- package/lib/disk-pressure.ts +42 -0
- package/lib/docker-exec.ts +156 -0
- package/lib/engine-accounts.ts +1970 -0
- package/lib/engine-connect.ts +321 -0
- package/lib/engine-credential-env.ts +52 -0
- package/lib/engine-login.ts +2933 -0
- package/lib/engines.ts +1342 -0
- package/lib/enrollment-state.ts +251 -0
- package/lib/env-file.ts +246 -0
- package/lib/env-schema.ts +891 -0
- package/lib/env.ts +195 -0
- package/lib/fs-aliases.ts +49 -0
- package/lib/git-clone-credentials.ts +334 -0
- package/lib/git-diff.ts +530 -0
- package/lib/git-identity.ts +715 -0
- package/lib/github-git-auth.ts +207 -0
- package/lib/github-origin.ts +28 -0
- package/lib/github-tokens.ts +2439 -0
- package/lib/host-cloud-url.ts +62 -0
- package/lib/host-config.ts +279 -0
- package/lib/host-env.ts +424 -0
- package/lib/host-logs.ts +965 -0
- package/lib/internal-connections.ts +5 -0
- package/lib/keyed-promise-tail.ts +23 -0
- package/lib/launch-mode.ts +25 -0
- package/lib/lease.ts +239 -0
- package/lib/legacy-host.ts +769 -0
- package/lib/legacy-runtime-retirement.ts +424 -0
- package/lib/legacy-runtime-v1.fixture.ts +627 -0
- package/lib/machine-exec.ts +238 -0
- package/lib/machine-gateway-tunnel.ts +344 -0
- package/lib/machine-keys.ts +65 -0
- package/lib/machine-project-env-loader.ts +152 -0
- package/lib/machine-provider-aws.ts +923 -0
- package/lib/machine-provider-local.ts +338 -0
- package/lib/machine-provider.ts +90 -0
- package/lib/managed-activation-watcher.ts +72 -0
- package/lib/managed-install-owner-watcher.ts +55 -0
- package/lib/managed-operation-drain.ts +57 -0
- package/lib/managed-runtime.ts +4296 -0
- package/lib/managed-update-scheduler.ts +125 -0
- package/lib/mcp-capture.ts +865 -0
- package/lib/mcp-config-lock.ts +2 -0
- package/lib/mcp-connections.ts +959 -0
- package/lib/mcp-gateway.ts +2594 -0
- package/lib/obs.ts +512 -0
- package/lib/openrouter-budget.ts +247 -0
- package/lib/orchestrator.ts +11409 -0
- package/lib/person-capture.ts +327 -0
- package/lib/preview-ports.ts +85 -0
- package/lib/preview-sidecar.ts +331 -0
- package/lib/project-env-authority.ts +1319 -0
- package/lib/project-env-feature.ts +74 -0
- package/lib/project-env-legacy-tags.ts +130 -0
- package/lib/project-env-loader.ts +242 -0
- package/lib/project-env-replica.ts +2094 -0
- package/lib/project-env-schema-capture.ts +342 -0
- package/lib/project-env-staging.ts +148 -0
- package/lib/project-env-task-policy.ts +176 -0
- package/lib/project-env-task-replica.ts +1752 -0
- package/lib/release-feed.ts +61 -0
- package/lib/release-manifest.ts +710 -0
- package/lib/release-trust.ts +46 -0
- package/lib/repo-clone.ts +38 -0
- package/lib/routing/shadow.ts +261 -0
- package/lib/runner-boot.ts +10 -0
- package/lib/runtime-activation-tail.ts +279 -0
- package/lib/runtime-archive.ts +1216 -0
- package/lib/runtime-authority.ts +166 -0
- package/lib/runtime-guard.ts +36 -0
- package/lib/runtime-provider-state.ts +169 -0
- package/lib/runtime-reconnect.ts +86 -0
- package/lib/runtime-state.ts +1033 -0
- package/lib/safe-http.ts +364 -0
- package/lib/secrets-proxy/address.ts +95 -0
- package/lib/secrets-proxy/audit.ts +30 -0
- package/lib/secrets-proxy/ca-store.ts +200 -0
- package/lib/secrets-proxy/ca.ts +470 -0
- package/lib/secrets-proxy/container-steps.ts +138 -0
- package/lib/secrets-proxy/der.ts +273 -0
- package/lib/secrets-proxy/engine.ts +1633 -0
- package/lib/secrets-proxy/host.ts +93 -0
- package/lib/secrets-proxy/hostname.ts +57 -0
- package/lib/secrets-proxy/placeholders.ts +196 -0
- package/lib/secrets-proxy/policy.ts +150 -0
- package/lib/secrets-proxy/readiness.ts +148 -0
- package/lib/secrets-proxy/runtime.ts +582 -0
- package/lib/secrets-proxy/scrub.ts +559 -0
- package/lib/secrets-proxy/sidecar-view.ts +139 -0
- package/lib/secrets-proxy/task-scripts.ts +262 -0
- package/lib/secrets-proxy/task-trust.ts +605 -0
- package/lib/secrets-proxy/trust-watch.ts +80 -0
- package/lib/secrets.ts +71 -0
- package/lib/shared-files-s3.ts +976 -0
- package/lib/shared-files.ts +156 -0
- package/lib/sidecar-assign.ts +49 -0
- package/lib/sidecar-guard.ts +58 -0
- package/lib/sidecar-resume.ts +178 -0
- package/lib/sidecar.ts +69 -0
- package/lib/signin-box-credentials.ts +465 -0
- package/lib/signin-box.ts +114 -0
- package/lib/skill-index-example.fixture.ts +56 -0
- package/lib/skill-layout.ts +417 -0
- package/lib/skills.ts +489 -0
- package/lib/ssh.ts +401 -0
- package/lib/standard-image-cleanup.ts +117 -0
- package/lib/standard-image-pin.ts +207 -0
- package/lib/standard-image.ts +1697 -0
- package/lib/stopped-task-status-queue.ts +120 -0
- package/lib/task-container-cli.ts +269 -0
- package/lib/task-credential-cleanup.ts +752 -0
- package/lib/task-diff-sandbox.ts +464 -0
- package/lib/task-diff.ts +91 -0
- package/lib/task-env-forwarder.ts +228 -0
- package/lib/task-env-source.ts +249 -0
- package/lib/task-environment/anchor.ts +31 -0
- package/lib/task-environment/apple-container.ts +860 -0
- package/lib/task-environment/docker.ts +1344 -0
- package/lib/task-environment/index.ts +466 -0
- package/lib/task-environment/legacy-adoption.ts +467 -0
- package/lib/task-environment/machine-environment.ts +61 -0
- package/lib/task-environment/machine-task-up.ts +1227 -0
- package/lib/task-environment/machine.ts +974 -0
- package/lib/task-environment/registry.ts +59 -0
- package/lib/task-environment/self-identity.ts +20 -0
- package/lib/task-environment/self.ts +566 -0
- package/lib/task-environment/types.ts +642 -0
- package/lib/task-environment/workspace-files.ts +685 -0
- package/lib/task-environment/workspace-runtime.fixture.ts +50 -0
- package/lib/task-files-machine-retirement-outbox.ts +592 -0
- package/lib/task-files-machine-retirement.ts +116 -0
- package/lib/task-files-readiness.ts +127 -0
- package/lib/task-gateway-port.ts +22 -0
- package/lib/task-gateway-protocol.ts +190 -0
- package/lib/task-gateway-recovery.ts +47 -0
- package/lib/task-gateway-state.ts +512 -0
- package/lib/task-identity.ts +19 -0
- package/lib/task-inventory.ts +682 -0
- package/lib/task-machine-credentials-activation.ts +95 -0
- package/lib/task-machine-swap-safety.ts +729 -0
- package/lib/task-person-credentials.ts +76 -0
- package/lib/task-project-ops-host.ts +147 -0
- package/lib/task-project-ops.ts +1062 -0
- package/lib/task-secret-staging.ts +16 -0
- package/lib/task-status.ts +46 -0
- package/lib/task-token.ts +46 -0
- package/lib/token-broker-adopt.ts +344 -0
- package/lib/token-broker-lambda.ts +105 -0
- package/lib/token-broker-local.ts +392 -0
- package/lib/token-broker-revision.ts +310 -0
- package/lib/token-broker-ssm.ts +525 -0
- package/lib/token-broker.ts +218 -0
- package/lib/token-lanes/openai-oauth.ts +123 -0
- package/lib/token-lanes/registry.ts +45 -0
- package/lib/token-lanes/types.ts +163 -0
- package/lib/token-lanes/xai-oauth.ts +165 -0
- package/lib/transcript.ts +128 -0
- package/lib/tunnel-registry.ts +220 -0
- package/lib/tunnel-runtime.ts +235 -0
- package/lib/ulid.ts +16 -0
- package/lib/user-bus-env.ts +116 -0
- package/lib/user-credentials-store.ts +435 -0
- package/lib/vnode-pressure.ts +142 -0
- package/package.json +115 -8
- package/runner/runner.mjs +442 -0
- package/scripts/agent/_common.sh +633 -0
- package/scripts/agent/env-hook.sh +626 -0
- package/scripts/agent/moondeck-cli.sh +5 -0
- package/scripts/agent/task-down.sh +291 -0
- package/scripts/agent/task-status.sh +70 -0
- package/scripts/agent/task-up.sh +3761 -0
- package/scripts/agent/uai-env-exec.sh +26 -0
- package/scripts/install/darwin.ts +1048 -0
- package/scripts/install/linux.ts +958 -0
- package/scripts/install/types.ts +78 -0
- package/scripts/install/util.ts +254 -0
- package/scripts/install/win.ts +143 -0
- package/src/activation-respawn.ts +155 -0
- package/src/apple-tunnel-route.ts +104 -0
- package/src/capture-wire.ts +102 -0
- package/src/cli.ts +2583 -0
- package/src/cloud-credentials.ts +2144 -0
- package/src/cloud-origins.ts +23 -0
- package/src/credential-location.ts +248 -0
- package/src/credential-wire-validation.ts +25 -0
- package/src/custom-connections.ts +237 -0
- package/src/engine-account-paths.ts +11 -0
- package/src/engine-models.ts +39 -0
- package/src/engine-usage.ts +104 -0
- package/src/event-outbox.ts +185 -0
- package/src/index.ts +2899 -0
- package/src/load-env.ts +97 -0
- package/src/machine-tunnel-route.ts +156 -0
- package/src/main.ts +6349 -0
- package/src/never-proxied-domains.ts +31 -0
- package/src/outbound-frame.ts +31 -0
- package/src/paths.ts +81 -0
- package/src/project-env-latest.ts +130 -0
- package/src/project-env-policy.ts +396 -0
- package/src/project-env-wording.ts +53 -0
- package/src/protocol.ts +5545 -0
- package/src/runtime-bootstrap.ts +165 -0
- package/src/station-identity.ts +96 -0
- package/src/task-env-names.ts +28 -0
- package/src/task-secrets.ts +75 -0
- package/src/tunnel-dial.ts +102 -0
- package/src/ui/server.ts +852 -0
- package/src/ui/types.ts +173 -0
- package/src/workspace-path-policy.ts +41 -0
- package/ui/app.js +1102 -0
- package/ui/index.html +90 -0
- package/ui/style.css +685 -0
- package/ui/uai-favicon.svg +21 -0
- package/ui/uai-logo-black.svg +9 -0
- package/ui/uai-wheel.svg +9 -0
- package/bin/moondeck-station.mjs +0 -3
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-114: the standard image is prebuilt in CI and pulled by digest.
|
|
3
|
+
*
|
|
4
|
+
* This module is the shared identity/grammar core, deliberately free of any
|
|
5
|
+
* host runtime import so the release-side identity script and the unit tests
|
|
6
|
+
* can load it without dragging the container-runtime graph along. Everything
|
|
7
|
+
* here is consumed from three places:
|
|
8
|
+
*
|
|
9
|
+
* - CI (`host-agent/scripts/release/standard-image-identity.ts`) computes
|
|
10
|
+
* the superset context hash and the registry tag to build/push.
|
|
11
|
+
* - Release packaging (`scripts/host-runtime/stage.mjs`) embeds a validated
|
|
12
|
+
* pin file in the signed payload (its .mjs copy of the grammar cites this
|
|
13
|
+
* module as authoritative).
|
|
14
|
+
* - The host (`standard-image.ts`) reads the packaged pin and pulls by
|
|
15
|
+
* digest instead of building, falling back to the local build.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
|
|
22
|
+
/** Image label carrying the build-context content hash (rebuild trigger). */
|
|
23
|
+
export const CONTEXT_HASH_LABEL = "com.runuai.context-hash";
|
|
24
|
+
|
|
25
|
+
/** The public registry repository CI publishes the prebuilt image to. The
|
|
26
|
+
* GitHub org was renamed runuai → moondeckio on 2026-10-20; GHCR, unlike
|
|
27
|
+
* github.com, does not redirect the old owner (pushes fail "owner not
|
|
28
|
+
* found", pulls 404). */
|
|
29
|
+
export const STANDARD_IMAGE_RELEASE_REF = "ghcr.io/moondeckio/uai-standard";
|
|
30
|
+
|
|
31
|
+
/** Pin file basename; packaged at `agent/images/<basename>` in the payload,
|
|
32
|
+
* one directory above the build context so it never perturbs the hash. */
|
|
33
|
+
export const STANDARD_IMAGE_PIN_BASENAME = "standard-image.pin.json";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The prebuilt image is the SUPERSET: every optional engine baked in. The
|
|
37
|
+
* layers are additive and non-fatal, a disabled engine is simply never
|
|
38
|
+
* invoked, and superset-vs-config means one published image serves every
|
|
39
|
+
* host — and toggling an engine on stops forcing a host-side rebuild.
|
|
40
|
+
*/
|
|
41
|
+
export const STANDARD_IMAGE_SUPERSET_EXTRA =
|
|
42
|
+
"kimi=1;grok=1;cursor=1;opencode=1";
|
|
43
|
+
|
|
44
|
+
export const STANDARD_IMAGE_SUPERSET_BUILD_ARGS: readonly string[] = [
|
|
45
|
+
"INSTALL_KIMI=1",
|
|
46
|
+
"INSTALL_GROK=1",
|
|
47
|
+
"INSTALL_CURSOR=1",
|
|
48
|
+
"INSTALL_OPENCODE=1",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
export interface StandardImagePin {
|
|
52
|
+
readonly ref: string;
|
|
53
|
+
readonly digest: string;
|
|
54
|
+
readonly contextHash: string;
|
|
55
|
+
/**
|
|
56
|
+
* Per-architecture image digests. A host pulls ITS OWN architecture's
|
|
57
|
+
* digest — pulling the manifest-list digest stores a two-variant image on
|
|
58
|
+
* the Apple runtime, and task-up's apple guard refuses any task image with
|
|
59
|
+
* more than one variant (found live on the Air's first task, 2026-08-20).
|
|
60
|
+
* Optional so a list-only pin still works on Docker via `digest`.
|
|
61
|
+
*/
|
|
62
|
+
readonly platforms?: { readonly arm64?: string; readonly x64?: string };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// The pin arrives inside a signature-verified payload; this grammar is
|
|
66
|
+
// defense-in-depth so no parsed field can smuggle registry ports, tags,
|
|
67
|
+
// or shell-significant bytes into an engine command line.
|
|
68
|
+
const REF_PATTERN = /^[a-z0-9]+(?:[a-z0-9._-]*[a-z0-9])?(?:\/[a-z0-9]+(?:[a-z0-9._-]*[a-z0-9])?)+$/;
|
|
69
|
+
const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;
|
|
70
|
+
const CONTEXT_HASH_PATTERN = /^[a-f0-9]{32}$/;
|
|
71
|
+
|
|
72
|
+
/** Strict parse of a pin document; null on ANY deviation. */
|
|
73
|
+
export function parseStandardImagePin(raw: string): StandardImagePin | null {
|
|
74
|
+
let parsed: unknown;
|
|
75
|
+
try {
|
|
76
|
+
parsed = JSON.parse(raw);
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
81
|
+
const { ref, digest, contextHash, platforms } = parsed as Record<
|
|
82
|
+
string,
|
|
83
|
+
unknown
|
|
84
|
+
>;
|
|
85
|
+
if (
|
|
86
|
+
typeof ref !== "string" ||
|
|
87
|
+
typeof digest !== "string" ||
|
|
88
|
+
typeof contextHash !== "string" ||
|
|
89
|
+
!REF_PATTERN.test(ref) ||
|
|
90
|
+
!DIGEST_PATTERN.test(digest) ||
|
|
91
|
+
!CONTEXT_HASH_PATTERN.test(contextHash)
|
|
92
|
+
) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
let parsedPlatforms: { arm64?: string; x64?: string } | undefined;
|
|
96
|
+
if (platforms !== undefined) {
|
|
97
|
+
if (typeof platforms !== "object" || platforms === null) return null;
|
|
98
|
+
parsedPlatforms = {};
|
|
99
|
+
for (const arch of ["arm64", "x64"] as const) {
|
|
100
|
+
const value = (platforms as Record<string, unknown>)[arch];
|
|
101
|
+
if (value === undefined) continue;
|
|
102
|
+
if (typeof value !== "string" || !DIGEST_PATTERN.test(value)) return null;
|
|
103
|
+
parsedPlatforms[arch] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
ref,
|
|
108
|
+
digest,
|
|
109
|
+
contextHash,
|
|
110
|
+
...(parsedPlatforms ? { platforms: parsedPlatforms } : {}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The digest a given host should pull: its own architecture's single-variant
|
|
116
|
+
* image when the pin carries one, else the manifest list. Docker resolves a
|
|
117
|
+
* list to the native variant; the Apple runtime stores the whole index, which
|
|
118
|
+
* task-up's one-variant guard then refuses — so arch digests win.
|
|
119
|
+
*/
|
|
120
|
+
export function standardImagePullDigest(
|
|
121
|
+
pin: StandardImagePin,
|
|
122
|
+
arch: string = process.arch,
|
|
123
|
+
): string {
|
|
124
|
+
if (arch === "arm64" || arch === "x64") {
|
|
125
|
+
const platformDigest = pin.platforms?.[arch];
|
|
126
|
+
if (platformDigest !== undefined) return platformDigest;
|
|
127
|
+
}
|
|
128
|
+
return pin.digest;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The exact engine argv for pulling and tagging the pinned image. Docker
|
|
132
|
+
* and the Apple `container` CLI differ only in the `image` subcommand prefix. */
|
|
133
|
+
export function standardImagePullCommands(
|
|
134
|
+
pin: StandardImagePin,
|
|
135
|
+
targetTag: string,
|
|
136
|
+
apple: boolean,
|
|
137
|
+
arch: string = process.arch,
|
|
138
|
+
): { pull: string[]; tag: string[] } {
|
|
139
|
+
const source = `${pin.ref}@${standardImagePullDigest(pin, arch)}`;
|
|
140
|
+
return apple
|
|
141
|
+
? {
|
|
142
|
+
pull: ["image", "pull", source],
|
|
143
|
+
tag: ["image", "tag", source, targetTag],
|
|
144
|
+
}
|
|
145
|
+
: { pull: ["pull", source], tag: ["tag", source, targetTag] };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Content-hash a standard-image build context: every file under the context
|
|
150
|
+
* dir, sorted by relative path, plus an `extra` string carrying the build-arg
|
|
151
|
+
* configuration (part of the image identity). Null when the context can't be
|
|
152
|
+
* read — callers keep whatever image exists.
|
|
153
|
+
*/
|
|
154
|
+
export async function hashStandardImageContext(
|
|
155
|
+
contextDir: string,
|
|
156
|
+
extra = "",
|
|
157
|
+
): Promise<string | null> {
|
|
158
|
+
try {
|
|
159
|
+
const files: string[] = [];
|
|
160
|
+
const walk = async (dir: string, prefix: string): Promise<void> => {
|
|
161
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
162
|
+
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
163
|
+
if (entry.isDirectory()) await walk(join(dir, entry.name), rel);
|
|
164
|
+
else files.push(rel);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
await walk(contextDir, "");
|
|
168
|
+
files.sort();
|
|
169
|
+
const hash = createHash("sha256");
|
|
170
|
+
for (const rel of files) {
|
|
171
|
+
hash.update(rel);
|
|
172
|
+
hash.update("\0");
|
|
173
|
+
hash.update(await readFile(join(contextDir, rel)));
|
|
174
|
+
hash.update("\0");
|
|
175
|
+
}
|
|
176
|
+
hash.update(extra);
|
|
177
|
+
hash.update("\0");
|
|
178
|
+
return hash.digest("hex").slice(0, 32);
|
|
179
|
+
} catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Everything CI needs to build/push/pin one release image, or null when the
|
|
185
|
+
* context is unreadable (a broken checkout must fail the release loudly). */
|
|
186
|
+
export async function standardImageReleaseIdentity(
|
|
187
|
+
contextDir: string,
|
|
188
|
+
): Promise<{
|
|
189
|
+
ref: string;
|
|
190
|
+
tag: string;
|
|
191
|
+
contextHash: string;
|
|
192
|
+
label: string;
|
|
193
|
+
buildArgs: readonly string[];
|
|
194
|
+
} | null> {
|
|
195
|
+
const contextHash = await hashStandardImageContext(
|
|
196
|
+
contextDir,
|
|
197
|
+
STANDARD_IMAGE_SUPERSET_EXTRA,
|
|
198
|
+
);
|
|
199
|
+
if (contextHash === null) return null;
|
|
200
|
+
return {
|
|
201
|
+
ref: STANDARD_IMAGE_RELEASE_REF,
|
|
202
|
+
tag: `ctx-${contextHash}`,
|
|
203
|
+
contextHash,
|
|
204
|
+
label: `${CONTEXT_HASH_LABEL}=${contextHash}`,
|
|
205
|
+
buildArgs: STANDARD_IMAGE_SUPERSET_BUILD_ARGS,
|
|
206
|
+
};
|
|
207
|
+
}
|