INFD-WP-0010-T02: owner-CI workflow for the full service image
All checks were successful
Build and Publish Service Image / build-and-push (push) Successful in 2m38s
All checks were successful
Build and Publish Service Image / build-and-push (push) Successful in 2m38s
.forgejo/workflows/service-image.yaml builds Containerfile from the pushed commit's tarball and pushes forgejo.coulomb.social/coulomb/informed-decision :main-<short sha>, then reports the immutable digest. Before pushing it checks the zlib floor, the runtime smoke (tools/zlib_overlay/check_runtime.py) and that the installed modules equal the commit's source. Containerfile builds the wheel in-image (hash-pinned setuptools in requirements-build.lock) and installs the zlib overlay's hash-pinned, Alpine-signed zlib-1.3.2-r1 package offline, failing below 1.3.2-r1, so the live image's zlib fix cannot regress. Overlay workflows are unchanged. Local build: 13/13 container checks, zlib 1.3.2-r1, source manifest match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 5502@bnt-lap001 Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
This commit is contained in:
parent
0ef57537ac
commit
c228583b60
9 changed files with 211 additions and 5 deletions
|
|
@ -1,5 +1,11 @@
|
||||||
**
|
**
|
||||||
!Containerfile
|
!Containerfile
|
||||||
!requirements.lock
|
!requirements.lock
|
||||||
!dist/
|
!requirements-build.lock
|
||||||
!dist/informed_decision-*.whl
|
!pyproject.toml
|
||||||
|
!informed_decision/
|
||||||
|
!informed_decision/**
|
||||||
|
**/__pycache__
|
||||||
|
**/*.pyc
|
||||||
|
!deploy/zlib-overlay/zlib-1.3.2-r1.apk
|
||||||
|
!deploy/zlib-overlay/APKINDEX.tar.gz
|
||||||
|
|
|
||||||
98
.forgejo/workflows/service-image.yaml
Normal file
98
.forgejo/workflows/service-image.yaml
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
name: Build and Publish Service Image
|
||||||
|
|
||||||
|
# Full informed-decision service image (INFD-WP-0010-T02 release path). Modelled on the fleet's
|
||||||
|
# canonical image-publish pattern (activity-core, access-engine, state-hub memo-dispatch): CI
|
||||||
|
# builds from a tarball of the pushed commit, never from a workstation working tree, so the
|
||||||
|
# artifact's provenance is a forge revision. The wheel is built inside the image from source.
|
||||||
|
#
|
||||||
|
# zlib: the Containerfile installs the same hash-pinned, Alpine-signed zlib-1.3.2-r1 package the
|
||||||
|
# zlib overlay uses (deploy/zlib-overlay), offline, and fails the build unless zlib >= 1.3.2-r1.
|
||||||
|
# This job re-checks that in the built image before anything is pushed.
|
||||||
|
#
|
||||||
|
# The purpose-overlay and zlib-overlay workflows are separate and unchanged. Publication is not
|
||||||
|
# deployment: pins move by digest in deploy/lifecycle/ under the founder-run release runbook.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- ".forgejo/workflows/service-image.yaml"
|
||||||
|
- "Containerfile"
|
||||||
|
- ".dockerignore"
|
||||||
|
- "requirements.lock"
|
||||||
|
- "requirements-build.lock"
|
||||||
|
- "pyproject.toml"
|
||||||
|
- "informed_decision/**"
|
||||||
|
- "deploy/zlib-overlay/zlib-1.3.2-r1.apk"
|
||||||
|
- "deploy/zlib-overlay/APKINDEX.tar.gz"
|
||||||
|
- "tools/service_image/**"
|
||||||
|
- "tools/zlib_overlay/check_runtime.py"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: informed-decision-service-image
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: forgejo.coulomb.social
|
||||||
|
IMAGE_NAME: coulomb/informed-decision
|
||||||
|
DOCKER_HOST: tcp://127.0.0.1:2375
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: container-build
|
||||||
|
steps:
|
||||||
|
- name: Build, check and push image
|
||||||
|
env:
|
||||||
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
REF="${GITHUB_SHA:?full source revision required}"
|
||||||
|
echo "${REF}" | grep -Eq '^[0-9a-f]{40}$'
|
||||||
|
test "${GITHUB_REPOSITORY}" = "coulomb/informed-decision"
|
||||||
|
if [ -z "${REGISTRY_USER:-}" ] || [ -z "${REGISTRY_TOKEN:-}" ]; then
|
||||||
|
echo "Admitted repository registry publication capability is unavailable; no borrowed credential is permitted." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
SHORT="$(printf '%s' "${REF}" | cut -c1-7)"
|
||||||
|
mkdir -p buildctx "${HOME}/bin"
|
||||||
|
wget -qO /tmp/repo.tar.gz \
|
||||||
|
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${REF}.tar.gz"
|
||||||
|
tar xzf /tmp/repo.tar.gz -C buildctx --strip-components=1
|
||||||
|
wget -qO- https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
|
||||||
|
| tar xz --strip-components=1 -C "${HOME}/bin" docker/docker
|
||||||
|
export PATH="${HOME}/bin:${PATH}"
|
||||||
|
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin
|
||||||
|
IMAGE="${REGISTRY}/${IMAGE_NAME}:main-${SHORT}"
|
||||||
|
docker build --label "org.opencontainers.image.revision=${REF}" \
|
||||||
|
-f buildctx/Containerfile -t "${IMAGE}" buildctx
|
||||||
|
# Checks before publication: zlib floor, runtime compression/crypto smoke, exact source.
|
||||||
|
docker run --rm --network none --read-only --entrypoint sh "${IMAGE}" \
|
||||||
|
-c "apk info --exists 'zlib>=1.3.2-r1' >/dev/null"
|
||||||
|
docker run --rm -i --network none --read-only --entrypoint python "${IMAGE}" - \
|
||||||
|
< buildctx/tools/zlib_overlay/check_runtime.py > /tmp/runtime.json
|
||||||
|
grep -q '"zlib_runtime_version": "1.3.2' /tmp/runtime.json
|
||||||
|
grep -q '"uid": 10001' /tmp/runtime.json
|
||||||
|
docker run --rm -i --network none --read-only --entrypoint python "${IMAGE}" - \
|
||||||
|
< buildctx/tools/service_image/installed_manifest.py > /tmp/installed.txt
|
||||||
|
(cd buildctx/informed_decision && find . -name '*.py' -not -path '*/__pycache__/*' \
|
||||||
|
| LC_ALL=C sort | xargs sha256sum) > /tmp/source.txt
|
||||||
|
diff /tmp/source.txt /tmp/installed.txt
|
||||||
|
docker push "${IMAGE}"
|
||||||
|
echo "pushed ${IMAGE} from ${REF}"
|
||||||
|
|
||||||
|
- name: Report immutable digest
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
export PATH="${HOME}/bin:${PATH}"
|
||||||
|
SHORT="$(printf '%s' "${GITHUB_SHA}" | cut -c1-7)"
|
||||||
|
IMAGE="${REGISTRY}/${IMAGE_NAME}:main-${SHORT}"
|
||||||
|
# Deployments pin by digest, never by tag -- print it for the release step.
|
||||||
|
docker inspect --format='{{index .RepoDigests 0}}' "${IMAGE}"
|
||||||
|
echo "source_revision=${GITHUB_SHA}"
|
||||||
|
echo "candidate_only=true; the founder-run release runbook pins this digest"
|
||||||
|
|
@ -1,15 +1,36 @@
|
||||||
# Base matches the approved Approval Engine Alpine family; scan each candidate.
|
# Base matches the approved Approval Engine Alpine family; scan each candidate.
|
||||||
|
# Built by owner CI (.forgejo/workflows/service-image.yaml) from a tarball of the pushed commit; the
|
||||||
|
# wheel is built inside the image from source, so no workstation dist/ is involved.
|
||||||
|
FROM python:3.12-alpine@sha256:b64631e04e4920160c50fbe8d8df828f7f35f06f425cb44aa09bca53e708a35a AS wheel
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||||
|
COPY requirements-build.lock /src/requirements-build.lock
|
||||||
|
RUN pip install --no-cache-dir --require-hashes --only-binary=:all: -r /src/requirements-build.lock
|
||||||
|
COPY pyproject.toml /src/pyproject.toml
|
||||||
|
COPY informed_decision /src/informed_decision
|
||||||
|
RUN pip wheel --no-cache-dir --no-deps --no-build-isolation --wheel-dir /dist /src
|
||||||
|
|
||||||
FROM python:3.12-alpine@sha256:b64631e04e4920160c50fbe8d8df828f7f35f06f425cb44aa09bca53e708a35a AS build
|
FROM python:3.12-alpine@sha256:b64631e04e4920160c50fbe8d8df828f7f35f06f425cb44aa09bca53e708a35a AS build
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PATH=/opt/venv/bin:$PATH
|
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PATH=/opt/venv/bin:$PATH
|
||||||
RUN python -m venv /opt/venv
|
RUN python -m venv /opt/venv
|
||||||
COPY requirements.lock /build/requirements.lock
|
COPY requirements.lock /build/requirements.lock
|
||||||
RUN pip install --no-cache-dir --require-hashes --only-binary=:all: -r /build/requirements.lock
|
RUN pip install --no-cache-dir --require-hashes --only-binary=:all: -r /build/requirements.lock
|
||||||
COPY dist/informed_decision-*.whl /build/
|
COPY --from=wheel /dist/ /build/
|
||||||
RUN pip install --no-cache-dir --no-deps --no-index /build/informed_decision-*.whl
|
RUN pip install --no-cache-dir --no-deps --no-index /build/informed_decision-*.whl
|
||||||
|
|
||||||
FROM python:3.12-alpine@sha256:b64631e04e4920160c50fbe8d8df828f7f35f06f425cb44aa09bca53e708a35a
|
FROM python:3.12-alpine@sha256:b64631e04e4920160c50fbe8d8df828f7f35f06f425cb44aa09bca53e708a35a
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PATH=/opt/venv/bin:$PATH
|
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PATH=/opt/venv/bin:$PATH
|
||||||
|
# zlib >= 1.3.2-r1 (INFD-WP-0009-T05 remediation, live since 2026-10-11 in f5588f49): the same
|
||||||
|
# hash-pinned, Alpine-signed package the zlib overlay installs, upgraded offline. The build fails
|
||||||
|
# if the result is older; a newer zlib already in the base is left as is.
|
||||||
|
COPY deploy/zlib-overlay/zlib-1.3.2-r1.apk deploy/zlib-overlay/APKINDEX.tar.gz /tmp/infd-zlib/x86_64/
|
||||||
|
RUN echo '63aeea03c15a2f9018f81805cfc8aa926bdf5cd68921f22149c2fbb5d0ee9f47 /tmp/infd-zlib/x86_64/zlib-1.3.2-r1.apk' | sha256sum -c - \
|
||||||
|
&& echo '24fc2ccb08f3125429a38b31bd6c76a7b394c6236df0975760dc8259e50dfbd5 /tmp/infd-zlib/x86_64/APKINDEX.tar.gz' | sha256sum -c - \
|
||||||
|
&& apk verify /tmp/infd-zlib/x86_64/zlib-1.3.2-r1.apk /tmp/infd-zlib/x86_64/APKINDEX.tar.gz \
|
||||||
|
&& apk upgrade --no-logfile --no-network --no-cache --no-preupgrade --repositories-file /dev/null --repository /tmp/infd-zlib zlib \
|
||||||
|
&& apk info --exists 'zlib>=1.3.2-r1' \
|
||||||
|
&& rm -rf /tmp/infd-zlib
|
||||||
RUN apk add --no-cache 'libuuid>=2.42.3-r1' \
|
RUN apk add --no-cache 'libuuid>=2.42.3-r1' \
|
||||||
|
&& apk info --exists 'zlib>=1.3.2-r1' \
|
||||||
&& addgroup -S -g 10001 informed \
|
&& addgroup -S -g 10001 informed \
|
||||||
&& adduser -S -u 10001 -G informed -H informed
|
&& adduser -S -u 10001 -G informed -H informed
|
||||||
COPY --from=build /opt/venv /opt/venv
|
COPY --from=build /opt/venv /opt/venv
|
||||||
|
|
|
||||||
2
Makefile
2
Makefile
|
|
@ -5,7 +5,7 @@ IMAGE ?= informed-decision:local
|
||||||
package:
|
package:
|
||||||
uv build --wheel
|
uv build --wheel
|
||||||
|
|
||||||
image-build: package
|
image-build:
|
||||||
docker build -f Containerfile -t $(IMAGE) .
|
docker build -f Containerfile -t $(IMAGE) .
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,14 @@ its own workflow, and it must keep zlib at `1.3.2-r1` or later. A plain rebuild
|
||||||
pinned `python:3.12-alpine@sha256:b64631e0…` base and only adds `libuuid`. That would reintroduce the zlib
|
pinned `python:3.12-alpine@sha256:b64631e0…` base and only adds `libuuid`. That would reintroduce the zlib
|
||||||
finding that the live image `f5588f49…` remediated. Then pin the image as in step 0.
|
finding that the live image `f5588f49…` remediated. Then pin the image as in step 0.
|
||||||
|
|
||||||
|
**Update, same day:** the full-image workflow now exists in source: `.forgejo/workflows/service-image.yaml`. It
|
||||||
|
builds `Containerfile` from the pushed commit's tarball, with the wheel built in-image. It installs the overlay's
|
||||||
|
hash-pinned zlib-1.3.2-r1 package offline and enforces `zlib>=1.3.2-r1`. It checks the runtime smoke and that the
|
||||||
|
installed source matches the commit before pushing `forgejo.coulomb.social/coulomb/informed-decision:main-<short sha>`,
|
||||||
|
then prints the digest in "Report immutable digest". A local build of the same Containerfile passed 13/13 container
|
||||||
|
checks (`tools/smoke_container.py --workload`), with zlib 1.3.2-r1 and the installed modules identical to source.
|
||||||
|
The gate is now: the push runs this workflow, then step 0 pins the digest it reports.
|
||||||
|
|
||||||
**Do not sync this candidate with the current image.** The live image `f5588f49…` accepts only the four basic
|
**Do not sync this candidate with the current image.** The live image `f5588f49…` accepts only the four basic
|
||||||
registry keys: `set(row) != {submitter_id, memo_classes, review_groups, daily_limit}`. It would reject the
|
registry keys: `set(row) != {submitter_id, memo_classes, review_groups, daily_limit}`. It would reject the
|
||||||
executor row, so every intake request would fail with 503 `intake_configuration_unavailable`, State Hub's
|
executor row, so every intake request would fail with 503 `intake_configuration_unavailable`, State Hub's
|
||||||
|
|
@ -59,7 +67,7 @@ Candidate source changes in this commit:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/informed-decision
|
cd ~/informed-decision
|
||||||
docker buildx imagetools inspect forgejo.coulomb.social/coulomb/informed-decision:<CI_TAG> # read the digest
|
docker buildx imagetools inspect forgejo.coulomb.social/coulomb/informed-decision:main-<short sha> # or the CI "Report immutable digest" line
|
||||||
# set "image" in deploy/lifecycle/admission.candidate.json to forgejo.coulomb.social/coulomb/informed-decision@<IMAGE_DIGEST>
|
# set "image" in deploy/lifecycle/admission.candidate.json to forgejo.coulomb.social/coulomb/informed-decision@<IMAGE_DIGEST>
|
||||||
python3 tools/render_deployment.py --input deploy/lifecycle/admission.candidate.json \
|
python3 tools/render_deployment.py --input deploy/lifecycle/admission.candidate.json \
|
||||||
--output deploy/lifecycle/service.candidate.json
|
--output deploy/lifecycle/service.candidate.json
|
||||||
|
|
|
||||||
4
requirements-build.lock
Normal file
4
requirements-build.lock
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Build backend for the in-image wheel stage (Containerfile). Hash-pinned; pyproject requires setuptools>=68.
|
||||||
|
# Hash from https://pypi.org/pypi/setuptools/80.9.0/json (setuptools-80.9.0-py3-none-any.whl).
|
||||||
|
setuptools==80.9.0 \
|
||||||
|
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
|
||||||
52
tests/test_service_image_build.py
Normal file
52
tests/test_service_image_build.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
"""Static checks for the owner-CI full service image (.forgejo/workflows/service-image.yaml).
|
||||||
|
|
||||||
|
The built image itself is checked in CI (zlib floor, runtime smoke, installed source manifest)
|
||||||
|
and locally with tools/smoke_container.py; these tests keep the inputs consistent.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
ROOT = Path(__file__).parents[1]
|
||||||
|
ZLIB = ROOT / 'deploy' / 'zlib-overlay'
|
||||||
|
|
||||||
|
|
||||||
|
def test_containerfile_installs_the_overlay_zlib_package_and_enforces_the_floor():
|
||||||
|
text = (ROOT / 'Containerfile').read_text()
|
||||||
|
pins = json.loads((ZLIB / 'pins.json').read_text())['files']
|
||||||
|
for name in ('zlib-1.3.2-r1.apk', 'APKINDEX.tar.gz'):
|
||||||
|
actual = hashlib.sha256((ZLIB / name).read_bytes()).hexdigest()
|
||||||
|
assert actual == pins[name]
|
||||||
|
assert f"echo '{actual} /tmp/infd-zlib/x86_64/{name}' | sha256sum -c -" in text
|
||||||
|
assert '--no-network' in text and "apk info --exists 'zlib>=1.3.2-r1'" in text
|
||||||
|
# Every stage uses the same pinned base; the wheel is built from source, not a workstation dist/.
|
||||||
|
bases = re.findall(r'^FROM (\S+)', text, re.M)
|
||||||
|
assert len(bases) == 3 and len(set(bases)) == 1 and '@sha256:' in bases[0]
|
||||||
|
assert 'COPY dist/' not in text and 'COPY --from=wheel /dist/' in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_context_admits_exactly_the_inputs():
|
||||||
|
ignore = (ROOT / '.dockerignore').read_text().split()
|
||||||
|
assert ignore[0] == '**'
|
||||||
|
for path in ('Containerfile', 'requirements.lock', 'requirements-build.lock', 'pyproject.toml',
|
||||||
|
'informed_decision/**', 'deploy/zlib-overlay/zlib-1.3.2-r1.apk',
|
||||||
|
'deploy/zlib-overlay/APKINDEX.tar.gz'):
|
||||||
|
assert '!' + path in ignore
|
||||||
|
build_lock = (ROOT / 'requirements-build.lock').read_text()
|
||||||
|
assert re.search(r'^setuptools==[\d.]+ \\\n\s+--hash=sha256:[0-9a-f]{64}$', build_lock, re.M)
|
||||||
|
|
||||||
|
|
||||||
|
def test_workflow_builds_from_the_pushed_commit_and_reports_the_digest():
|
||||||
|
flow = yaml.safe_load((ROOT / '.forgejo' / 'workflows' / 'service-image.yaml').read_text())
|
||||||
|
on = flow.get('on', flow.get(True))
|
||||||
|
assert on['push']['branches'] == ['main']
|
||||||
|
steps = flow['jobs']['build-and-push']['steps']
|
||||||
|
script = steps[0]['run']
|
||||||
|
assert 'archive/${REF}.tar.gz' in script and ':main-${SHORT}' in script
|
||||||
|
assert script.index("zlib>=1.3.2-r1") < script.index('docker push')
|
||||||
|
assert script.index('diff /tmp/source.txt /tmp/installed.txt') < script.index('docker push')
|
||||||
|
assert steps[1]['name'] == 'Report immutable digest'
|
||||||
|
assert flow['env']['IMAGE_NAME'] == 'coulomb/informed-decision'
|
||||||
13
tools/service_image/installed_manifest.py
Normal file
13
tools/service_image/installed_manifest.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
"""Print `sha256 ./relative/path` for the installed informed_decision modules (C-sorted).
|
||||||
|
|
||||||
|
Run inside the service image (`docker run -i --entrypoint python IMAGE - < this file`). CI compares
|
||||||
|
the output with `sha256sum` over the pushed commit's informed_decision/*.py: the image must carry
|
||||||
|
exactly the source it was built from. Opens no database and no network.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path('/opt/venv/lib/python3.12/site-packages/informed_decision')
|
||||||
|
rows = sorted('./' + str(p.relative_to(ROOT)) for p in ROOT.rglob('*.py') if '__pycache__' not in p.parts)
|
||||||
|
for rel in rows:
|
||||||
|
print(hashlib.sha256((ROOT / rel).read_bytes()).hexdigest() + ' ' + rel)
|
||||||
|
|
@ -107,6 +107,10 @@ revision 13: `deploy/lifecycle/RELEASE-INFD-WP-0010-T02.md`. Tests: 704 passed,
|
||||||
workflows exist; purpose-overlay run 5 failed by design on the changed `policy.py` hash. The image pin is therefore
|
workflows exist; purpose-overlay run 5 failed by design on the changed `policy.py` hash. The image pin is therefore
|
||||||
still the live `f5588f49…`, and the candidate must not be synced until the pin is replaced by an owner-CI full image
|
still the live `f5588f49…`, and the candidate must not be synced until the pin is replaced by an owner-CI full image
|
||||||
that keeps zlib ≥ 1.3.2-r1. Nothing applied.
|
that keeps zlib ≥ 1.3.2-r1. Nothing applied.
|
||||||
|
Same day, step 0 in source: `.forgejo/workflows/service-image.yaml` builds the full image from the pushed commit and
|
||||||
|
publishes `main-<short sha>`. The `Containerfile` builds the wheel in-image and installs the overlay's hash-pinned
|
||||||
|
zlib-1.3.2-r1 offline, failing the build below 1.3.2-r1. A local build passed 13/13 container checks. The image pin
|
||||||
|
waits for the digest from CI.
|
||||||
|
|
||||||
Then here: the policy pin, a registry row, a release, and a native proof with synthetic BEA content. Optional: for
|
Then here: the policy pin, a registry row, a release, and a native proof with synthetic BEA content. Optional: for
|
||||||
`bounded-execution`, require a packet item whose digest equals `target.admission_digest`, once the admission
|
`bounded-execution`, require a packet item whose digest equals `target.admission_digest`, once the admission
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue