Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5362c3f
Separate the native AWS runtime wrapper
ChristianPavilonis Nov 11, 2026
f3432cb
Carry baseline check corrections into the next review unit
ChristianPavilonis Nov 11, 2026
a38bcfb
Carry the docs-only site correction into the next baseline unit
ChristianPavilonis Nov 11, 2026
3023e98
Carry the startup probe correction through the compatible baseline
ChristianPavilonis Nov 11, 2026
46f6211
Carry the browser CI host compatibility fix through the baseline
ChristianPavilonis Nov 11, 2026
3471dca
Carry the tagged EdgeZero snapshot through the stack
ChristianPavilonis Nov 11, 2026
ee5a389
Carry the monthly EdgeZero tag through the stack
ChristianPavilonis Nov 11, 2026
8d92229
Retain the literal native AWS runtime wrapper
ChristianPavilonis Nov 12, 2026
edf5968
Retain runtime-appropriate acceptance fixture storage
ChristianPavilonis Nov 12, 2026
9253166
Retain current main validation and mediator fallback
ChristianPavilonis Nov 12, 2026
d73300d
Retain the Cargo target-aware cache harness
ChristianPavilonis Nov 12, 2026
067fdef
Retain runtime-specific CLI smoke fixture coverage
ChristianPavilonis Nov 12, 2026
06a08bf
Retain target-aware GPT bundle lookup for the cache fixture
ChristianPavilonis Nov 12, 2026
4ab2f26
Carry hosted qualification fixes through PR 1538
ChristianPavilonis Nov 12, 2026
1cd2d75
Carry hosted qualification fixes through PR 1538
ChristianPavilonis Nov 12, 2026
fc227a4
Carry hosted qualification fixes through PR 1538
ChristianPavilonis Nov 12, 2026
57576f2
Carry hosted qualification fixes through PR 1538
ChristianPavilonis Nov 12, 2026
3111c24
Carry hosted qualification fixes through PR 1538
ChristianPavilonis Nov 12, 2026
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
35 changes: 35 additions & 0 deletions deploy/runtime/native-aws/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# syntax=docker/dockerfile:1
# Both inputs must be explicit accepted digest references. Build at repository root.
ARG TS_NATIVE_PROVIDER_IMAGE
ARG TS_NATIVE_RUNTIME_IMAGE
FROM ${TS_NATIVE_PROVIDER_IMAGE} AS binary-source
FROM ${TS_NATIVE_RUNTIME_IMAGE} AS runtime

ARG TS_NATIVE_PROVIDER_IMAGE
ARG TS_NATIVE_RUNTIME_IMAGE
# No runtime operation needs setuid/setgid tools. Nonroot alone is insufficient.
RUN set -eu; \
printf '%s\n' "$TS_NATIVE_PROVIDER_IMAGE" | grep -Eq '@sha256:[a-f0-9]{64}$'; \
printf '%s\n' "$TS_NATIVE_RUNTIME_IMAGE" | grep -Eq '@sha256:[a-f0-9]{64}$'; \
. /etc/os-release; test "$ID:$VERSION_ID" = debian:13; \
apt-get update; \
apt-get upgrade -y --no-install-recommends; \
Comment on lines +15 to +16

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 wrench — apt-get update && apt-get upgrade makes the image non-reproducible

Both inputs are digest-pinned, and the labels on lines 21-22 record those digests as though they describe the image. But update/upgrade/install pull whatever the Debian mirror serves at build time, so two builds from the same labelled inputs can produce different runtime layers, and the labels no longer describe what was reviewed. Pick one:

  • Drop apt-get upgrade and pin package versions (or rely on a refreshed runtime digest for security updates).
  • Pin the apt sources to a snapshot.debian.org timestamp and record that timestamp as a label.
  • At minimum, document in the README that the labels don't fully describe the runtime layer.

Apply manually. The right option is a design choice, not a mechanical edit.

apt-get install -y --no-install-recommends ca-certificates libgcc-s1 coreutils; \
rm -rf /var/lib/apt/lists/*; \
find / -xdev -type f -perm /6000 -exec chmod a-s {} +; \
install -d -m 0700 -o 10001 -g 10001 /run/trusted-server
LABEL ts.native.provider-image="${TS_NATIVE_PROVIDER_IMAGE}" \
ts.native.runtime-image="${TS_NATIVE_RUNTIME_IMAGE}"
WORKDIR /app
COPY --from=binary-source --chmod=0555 /usr/local/bin/app /usr/local/bin/app
COPY --from=binary-source /usr/local/share/ts-build-inputs.sha256 /usr/local/share/ts-build-inputs.sha256
COPY --chmod=0555 deploy/runtime/native-aws/entrypoint.sh /usr/local/bin/ts-native-entrypoint
ENV EDGEZERO__ADAPTER__HOST=0.0.0.0 \
EDGEZERO__ADAPTER__PORT=8787 \
EDGEZERO__STORE_BINDINGS_FILE=/run/trusted-server/native-bindings.toml
USER 10001:10001
# ECS must still qualify ownership on its matching task volume mount.
VOLUME ["/run/trusted-server"]
EXPOSE 8787
STOPSIGNAL SIGTERM
ENTRYPOINT ["/usr/local/bin/ts-native-entrypoint"]
7 changes: 7 additions & 0 deletions deploy/runtime/native-aws/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This overrides the root deny-by-default context for this Dockerfile only.
# Keep operator input/state/config files out of the deployment-image context.
**
!deploy/
!deploy/runtime/
!deploy/runtime/native-aws/
Comment on lines +4 to +6

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 wrench — These re-includes widen the context to all of deploy/, not just entrypoint.sh

Docker cleans !deploy/ to deploy and treats a match on any parent directory as a match for the file. So !deploy/ re-includes everything under deploy/ (for example a local deploy/pbs-example/terraform.tfvars), and !deploy/runtime/native-aws/ re-includes every file next to the entrypoint. That defeats the header comment ("Keep operator input/state/config files out of the deployment-image context"). An explicit file re-include is enough, because the builder walks excluded directories when a later ! rule could match inside them:

**
!deploy/runtime/native-aws/entrypoint.sh

Apply manually. This can't be a one-click suggestion because test-entrypoint.mjs (the "Dockerfile-specific context permits only the bootstrap script" test) pins the exact rule list and has to change too. Also note that only BuildKit reads Dockerfile.dockerignore. The legacy builder uses the root .dockerignore, which excludes deploy/, so the COPY on Dockerfile line 26 fails there. It's worth saying in the README that BuildKit is required.

!deploy/runtime/native-aws/entrypoint.sh
45 changes: 45 additions & 0 deletions deploy/runtime/native-aws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Native AWS runtime wrapper

This is the existing demo's runtime wrapper, separate from the source-built
native image. Build at the repository root and supply two explicit digest
references: `TS_NATIVE_PROVIDER_IMAGE` supplies the application binary and input
manifest; `TS_NATIVE_RUNTIME_IMAGE` supplies the Debian 13 runtime. The wrapper
neither builds TS nor provisions infrastructure. An accepted reference must name
the image whose inputs and runtime checks were actually reviewed; syntax alone
is not qualification.

The image runs as UID/GID10001. `/run/trusted-server` must be an owned, writable

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick — Missing space in UID/GID10001 (same on line 17, literal0600).

Suggested change
The image runs as UID/GID10001. `/run/trusted-server` must be an owned, writable
The image runs as UID/GID 10001. `/run/trusted-server` must be an owned, writable

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick — Missing space before the UID/GID value.

Suggested change
The image runs as UID/GID10001. `/run/trusted-server` must be an owned, writable
The image runs as UID/GID 10001. `/run/trusted-server` must be an owned, writable

private mount. Its declared volume does not establish ownership on an ECS task
volume; that remains a deployment check. Keep the root filesystem read-only and
provide required writable temporary storage when selecting that runtime mode.

`TS_NATIVE_BINDINGS_TOML` contains provider identifiers/references, never secret
values. The entrypoint publishes it as a literal0600 file under the private

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick — Missing space in literal0600.

Suggested change
values. The entrypoint publishes it as a literal0600 file under the private
values. The entrypoint publishes it as a literal 0600 file under the private

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick — Missing space before the file mode.

Suggested change
values. The entrypoint publishes it as a literal0600 file under the private
values. The entrypoint publishes it as a literal 0600 file under the private

runtime directory. Optional `TS_NATIVE_GEO_PROFILE_TOML` is published the same
way. Empty explicitly selected Geo input fails rather than selecting Off. With
no profile content, inherited pointers cannot enable Geo. The application owns
validation of both formats.

After publication the wrapper removes those input-content variables and the
local-provider directory defaults, then execs the application. It never sources
or evaluates TOML. SIGTERM reaches the application directly. AWS credentials and
referenced secret values belong to the selected runtime providers, not build
arguments or public examples.

```mermaid
flowchart TD
A[Reviewed native binary image] --> C[Separate runtime wrapper]
B[Explicit Debian runtime image] --> C
C --> D[Publish literal private provider files]
D --> E[Exec native TS and forward signals]
```

Run the retained local publication and signal tests with the repository Node:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick — On macOS (Node 24.12.0, matching .tool-versions) this command gives 7 pass / 7 fail, all mv: illegal option -- T. mv -T is right for the Debian image; the README just shouldn't imply the tests run on any host.

Suggested change
Run the retained local publication and signal tests with the repository Node:
Run the retained local publication and signal tests on Linux with the
repository Node. The entrypoint relies on GNU `mv -T`, which macOS lacks:


```sh
node --test deploy/runtime/native-aws/test-entrypoint.mjs
```

These tests do not establish that a selected binary/runtime image combination,
ECS volume, IAM role or live front door has been qualified. No cloud operation
or live input change belongs to this review unit.
50 changes: 50 additions & 0 deletions deploy/runtime/native-aws/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/sh
set -eu

# This input contains provider identifiers and references, never secret values.
if [ -z "${TS_NATIVE_BINDINGS_TOML:-}" ]; then
printf '%s\n' 'TS_NATIVE_BINDINGS_TOML is required' >&2
exit 1
fi

runtime_dir='/run/trusted-server'
if [ ! -d "$runtime_dir" ] || [ ! -w "$runtime_dir" ] || [ ! -x "$runtime_dir" ]; then
printf '%s\n' 'Native bindings directory must be writable' >&2
exit 1
fi

umask 077
temporary=$(mktemp "$runtime_dir/.native-bindings.XXXXXX")
trap 'rm -f "$temporary"' 0
trap 'exit 1' 1 2 15
# printf treats the entire input as data. Never source or evaluate these bytes.
printf '%s' "$TS_NATIVE_BINDINGS_TOML" > "$temporary"
chmod 0600 "$temporary"
mv -fT -- "$temporary" "$runtime_dir/native-bindings.toml"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 thinking — The publish path is fixed, but the app reads EDGEZERO__STORE_BINDINGS_FILE

The entrypoint always writes $runtime_dir/native-bindings.toml, while the application loads whatever EDGEZERO__STORE_BINDINGS_FILE points to. The Dockerfile sets the two to the same value, but a task definition that overrides the env var would make the app read a different (possibly stale or missing) file, and nothing would report it. Consider failing fast on a mismatch, for example:

if [ "${EDGEZERO__STORE_BINDINGS_FILE:-}" != "$runtime_dir/native-bindings.toml" ]; then
    printf '%s\n' 'EDGEZERO__STORE_BINDINGS_FILE must point at the published bindings file' >&2
    exit 1
fi

The test fixture sets EDGEZERO__STORE_BINDINGS_FILE to the relocated path, so the check would hold under the existing tests once the fixture's runtime_dir replacement is taken into account.

trap - 0 1 2 15

# An absent profile keeps Geo Off. An explicitly empty profile is an error,
# not an implicit fallback. The app owns typed parsing and provider selection.
if [ "${TS_NATIVE_GEO_PROFILE_TOML+x}" = x ]; then
if [ -z "$TS_NATIVE_GEO_PROFILE_TOML" ]; then
printf '%s\n' 'TS_NATIVE_GEO_PROFILE_TOML must not be empty' >&2
exit 1
fi
temporary=$(mktemp "$runtime_dir/.native-geo.XXXXXX")
trap 'rm -f "$temporary"' 0
trap 'exit 1' 1 2 15
printf '%s' "$TS_NATIVE_GEO_PROFILE_TOML" > "$temporary"
chmod 0600 "$temporary"
mv -fT -- "$temporary" "$runtime_dir/native-geo.toml"
trap - 0 1 2 15
TS_NATIVE_GEO_PROFILE_FILE="$runtime_dir/native-geo.toml"
export TS_NATIVE_GEO_PROFILE_FILE
else
# Do not let an inherited pointer or a previous volume file select Geo.
unset TS_NATIVE_GEO_PROFILE_FILE
fi

# The base image's local roots need not exist when both stores are remote.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 thinking — The runtime stage starts FROM ${TS_NATIVE_RUNTIME_IMAGE}, so it does not inherit the provider image's EDGEZERO__ADAPTER__CONFIG_DIR=/config / DATA_DIR=/data ENV. In practice this unset only discards roots an operator sets on the ECS task. If bindings then select a local store, startup fails with CONFIG_DIR required (EdgeZero 83d7a62, dev_server.rs:1283/:1332) — fail-closed, but with no hint the wrapper removed it. Behaviour is fine; the comment should say what actually happens.

Suggested change
# The base image's local roots need not exist when both stores are remote.
# The runtime image does not inherit the provider image's local roots. Drop any
# task-supplied roots too: this wrapper supports remote config/secret stores only.

unset EDGEZERO__ADAPTER__CONFIG_DIR EDGEZERO__ADAPTER__DATA_DIR
unset TS_NATIVE_BINDINGS_TOML TS_NATIVE_GEO_PROFILE_TOML
exec /usr/local/bin/app "$@"
Loading
Loading