build: freeze operating system package inputs
This commit is contained in:
@@ -41,6 +41,9 @@ jobs:
|
|||||||
npm install --package-lock-only --ignore-scripts --no-audit --no-fund
|
npm install --package-lock-only --ignore-scripts --no-audit --no-fund
|
||||||
)
|
)
|
||||||
done
|
done
|
||||||
|
python3 scripts/complete_npm_lock_integrity.py \
|
||||||
|
bot_bottle/contrib/claude/package-lock.json \
|
||||||
|
bot_bottle/contrib/pi/package-lock.json
|
||||||
|
|
||||||
- name: Refresh pinned Codex installer checksum
|
- name: Refresh pinned Codex installer checksum
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+11
-1
@@ -43,13 +43,23 @@
|
|||||||
# is pip-installed to the same effect as the upstream image.
|
# is pip-installed to the same effect as the upstream image.
|
||||||
FROM python:3.12.13-slim-trixie@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
|
FROM python:3.12.13-slim-trixie@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
|
||||||
|
|
||||||
|
# Freeze apt's package universe as well as the base filesystem. Without a
|
||||||
|
# snapshot, the same Dockerfile resolves different package versions over time.
|
||||||
|
ARG DEBIAN_SNAPSHOT=20260724T000000Z
|
||||||
|
RUN sed -i \
|
||||||
|
-e "s|http://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|http://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
/etc/apt/sources.list.d/debian.sources
|
||||||
|
|
||||||
# Runtime system deps:
|
# Runtime system deps:
|
||||||
# git supplies the `git daemon` subcommand (no separate package)
|
# git supplies the `git daemon` subcommand (no separate package)
|
||||||
# plus the core `git` binary the pre-receive hook invokes.
|
# plus the core `git` binary the pre-receive hook invokes.
|
||||||
# openssh-client supplies the upstream SSH transport the
|
# openssh-client supplies the upstream SSH transport the
|
||||||
# pre-receive hook uses to forward accepted refs.
|
# pre-receive hook uses to forward accepted refs.
|
||||||
# ca-certificates is needed for mitmdump upstream TLS.
|
# ca-certificates is needed for mitmdump upstream TLS.
|
||||||
RUN apt-get update \
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
git openssh-client ca-certificates \
|
git openssh-client ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|||||||
@@ -18,7 +18,15 @@
|
|||||||
ARG ORCHESTRATOR_BASE_IMAGE
|
ARG ORCHESTRATOR_BASE_IMAGE
|
||||||
FROM ${ORCHESTRATOR_BASE_IMAGE}
|
FROM ${ORCHESTRATOR_BASE_IMAGE}
|
||||||
|
|
||||||
RUN apt-get update \
|
ARG DEBIAN_SNAPSHOT=20260724T000000Z
|
||||||
|
RUN sed -i \
|
||||||
|
-e "s|http://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|http://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
/etc/apt/sources.list.d/debian.sources
|
||||||
|
|
||||||
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
buildah crun netavark aardvark-dns \
|
buildah crun netavark aardvark-dns \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
# Version-qualified Node LTS, pinned to its multi-architecture manifest.
|
# Version-qualified Node LTS, pinned to its multi-architecture manifest.
|
||||||
FROM node:22.23.1-trixie-slim@sha256:e6d9a389d34ff9678438af985c9913fbd1eb6ed36e80fea56644f4b4f6dd70ba
|
FROM node:22.23.1-trixie-slim@sha256:e6d9a389d34ff9678438af985c9913fbd1eb6ed36e80fea56644f4b4f6dd70ba
|
||||||
|
|
||||||
|
ARG DEBIAN_SNAPSHOT=20260724T000000Z
|
||||||
|
RUN sed -i \
|
||||||
|
-e "s|http://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|http://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
/etc/apt/sources.list.d/debian.sources
|
||||||
|
|
||||||
# Install runtime system deps. claude-code shells out to git for several
|
# Install runtime system deps. claude-code shells out to git for several
|
||||||
# features (status checks, commits, PR creation) — without git in the
|
# features (status checks, commits, PR creation) — without git in the
|
||||||
# image, those features fail in surprising ways once the user does any
|
# image, those features fail in surprising ways once the user does any
|
||||||
@@ -19,7 +27,7 @@ FROM node:22.23.1-trixie-slim@sha256:e6d9a389d34ff9678438af985c9913fbd1eb6ed36e8
|
|||||||
# HTTPS_PROXY-aware tool (curl itself, plus anything that shells out
|
# HTTPS_PROXY-aware tool (curl itself, plus anything that shells out
|
||||||
# to it) works against egress's bumped TLS without the agent needing
|
# to it) works against egress's bumped TLS without the agent needing
|
||||||
# local DNS.
|
# local DNS.
|
||||||
RUN apt-get update \
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
git \
|
git \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
@@ -34,7 +42,7 @@ RUN apt-get update \
|
|||||||
# (claude-code is a Node CLI), but is convenient for the agent to
|
# (claude-code is a Node CLI), but is convenient for the agent to
|
||||||
# shell out to for ad-hoc scripts. Kept on its own layer so it can
|
# shell out to for ad-hoc scripts. Kept on its own layer so it can
|
||||||
# be moved to a downstream image if the base ever needs to shrink.
|
# be moved to a downstream image if the base ever needs to shrink.
|
||||||
RUN apt-get update \
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
|
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,15 @@ FROM node:22.23.1-trixie-slim@sha256:e6d9a389d34ff9678438af985c9913fbd1eb6ed36e8
|
|||||||
# installer source and checksum.
|
# installer source and checksum.
|
||||||
ARG CODEX_VERSION=0.145.0
|
ARG CODEX_VERSION=0.145.0
|
||||||
|
|
||||||
RUN apt-get update \
|
ARG DEBIAN_SNAPSHOT=20260724T000000Z
|
||||||
|
RUN sed -i \
|
||||||
|
-e "s|http://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|http://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
/etc/apt/sources.list.d/debian.sources
|
||||||
|
|
||||||
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
git \
|
git \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
@@ -24,7 +32,7 @@ RUN apt-get update \
|
|||||||
# (codex is a Node CLI), but is convenient for the agent to shell
|
# (codex is a Node CLI), but is convenient for the agent to shell
|
||||||
# out to for ad-hoc scripts. Kept on its own layer so it can be
|
# out to for ad-hoc scripts. Kept on its own layer so it can be
|
||||||
# moved to a downstream image if the base ever needs to shrink.
|
# moved to a downstream image if the base ever needs to shrink.
|
||||||
RUN apt-get update \
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
|
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,15 @@
|
|||||||
|
|
||||||
FROM node:22.23.1-trixie-slim@sha256:e6d9a389d34ff9678438af985c9913fbd1eb6ed36e80fea56644f4b4f6dd70ba
|
FROM node:22.23.1-trixie-slim@sha256:e6d9a389d34ff9678438af985c9913fbd1eb6ed36e80fea56644f4b4f6dd70ba
|
||||||
|
|
||||||
RUN apt-get update \
|
ARG DEBIAN_SNAPSHOT=20260724T000000Z
|
||||||
|
RUN sed -i \
|
||||||
|
-e "s|http://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian-security|https://snapshot.debian.org/archive/debian-security/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|http://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
-e "s|https://deb.debian.org/debian|https://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}|g" \
|
||||||
|
/etc/apt/sources.list.d/debian.sources
|
||||||
|
|
||||||
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
git \
|
git \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
@@ -15,7 +23,7 @@ RUN apt-get update \
|
|||||||
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
|
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get -o Acquire::Check-Valid-Until=false update \
|
||||||
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
|
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
Generated
+6
-3
@@ -1056,7 +1056,8 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.19.0"
|
"node": ">=22.19.0"
|
||||||
}
|
},
|
||||||
|
"integrity": "sha512-yqbh68CyhqxMov/jUogFJfMqlu2Gd37GAki+tr59YCmAPHfomiCA5ESzusXtpGzABeiZFC/OrRdQ4GwCCOMIHA=="
|
||||||
},
|
},
|
||||||
"node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-ai": {
|
"node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-ai": {
|
||||||
"version": "0.81.1",
|
"version": "0.81.1",
|
||||||
@@ -1080,7 +1081,8 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.19.0"
|
"node": ">=22.19.0"
|
||||||
}
|
},
|
||||||
|
"integrity": "sha512-hzHE7Z8l5mgJk+ke67Lge0rwS2+wbKJrFKl9o5M1R1rh33+cCT7D1AHz1OAtX5wFs90E1/BTGhyJRTUHaMxGvQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui": {
|
"node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui": {
|
||||||
"version": "0.81.1",
|
"version": "0.81.1",
|
||||||
@@ -1092,7 +1094,8 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.19.0"
|
"node": ">=22.19.0"
|
||||||
}
|
},
|
||||||
|
"integrity": "sha512-OMEe+Zt8oQYi/rCq3upxsTlIScWL0FPhXwQus34TbQb3EmTx88S7Uzx32JxvQiEeWOw8eDCdJf2PBUBE9r6wIg=="
|
||||||
},
|
},
|
||||||
"node_modules/@earendil-works/pi-coding-agent/node_modules/@google/genai": {
|
"node_modules/@earendil-works/pi-coding-agent/node_modules/@google/genai": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Complete duplicate npm lock entries from an identical verified artifact."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def complete_lock(path: Path) -> int:
|
||||||
|
"""Fill missing SRI only from the same resolved URL; return change count."""
|
||||||
|
data = json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
packages = data.get("packages", {})
|
||||||
|
integrity_by_url: dict[str, str] = {}
|
||||||
|
for package in packages.values():
|
||||||
|
resolved = package.get("resolved")
|
||||||
|
integrity = package.get("integrity")
|
||||||
|
if not isinstance(resolved, str) or not resolved.startswith(
|
||||||
|
("http://", "https://"),
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
if not isinstance(integrity, str) or not integrity.startswith("sha512-"):
|
||||||
|
continue
|
||||||
|
prior = integrity_by_url.setdefault(resolved, integrity)
|
||||||
|
if prior != integrity:
|
||||||
|
raise ValueError(f"conflicting integrity values for {resolved}")
|
||||||
|
|
||||||
|
changed = 0
|
||||||
|
missing: list[str] = []
|
||||||
|
for package_path, package in packages.items():
|
||||||
|
resolved = package.get("resolved")
|
||||||
|
if not isinstance(resolved, str) or not resolved.startswith(
|
||||||
|
("http://", "https://"),
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
integrity = package.get("integrity")
|
||||||
|
if isinstance(integrity, str) and integrity.startswith("sha512-"):
|
||||||
|
continue
|
||||||
|
known = integrity_by_url.get(resolved)
|
||||||
|
if known is None:
|
||||||
|
missing.append(package_path)
|
||||||
|
continue
|
||||||
|
package["integrity"] = known
|
||||||
|
changed += 1
|
||||||
|
if missing:
|
||||||
|
joined = ", ".join(missing)
|
||||||
|
raise ValueError(f"no verified duplicate artifact for: {joined}")
|
||||||
|
if changed:
|
||||||
|
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("locks", nargs="+", type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
for path in args.locks:
|
||||||
|
changed = complete_lock(path)
|
||||||
|
print(f"{path}: completed {changed} duplicate integrity entries")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
"""Unit tests for npm's duplicate lock-entry integrity completion."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from scripts.complete_npm_lock_integrity import complete_lock
|
||||||
|
|
||||||
|
|
||||||
|
class TestCompleteLock(unittest.TestCase):
|
||||||
|
def _lock(self, directory: str, packages: dict[str, dict[str, str]]) -> Path:
|
||||||
|
path = Path(directory) / "package-lock.json"
|
||||||
|
path.write_text(json.dumps({
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"packages": packages,
|
||||||
|
}))
|
||||||
|
return path
|
||||||
|
|
||||||
|
def test_copies_integrity_only_for_identical_resolved_url(self):
|
||||||
|
url = "https://registry.npmjs.org/example/-/example-1.2.3.tgz"
|
||||||
|
integrity = "sha512-trusted"
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
path = self._lock(directory, {
|
||||||
|
"node_modules/example": {
|
||||||
|
"resolved": url,
|
||||||
|
"integrity": integrity,
|
||||||
|
},
|
||||||
|
"node_modules/parent/node_modules/example": {
|
||||||
|
"resolved": url,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
self.assertEqual(1, complete_lock(path))
|
||||||
|
packages = json.loads(path.read_text())["packages"]
|
||||||
|
self.assertEqual(
|
||||||
|
integrity,
|
||||||
|
packages["node_modules/parent/node_modules/example"]["integrity"],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_rejects_missing_integrity_without_verified_duplicate(self):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
path = self._lock(directory, {
|
||||||
|
"node_modules/example": {
|
||||||
|
"resolved": (
|
||||||
|
"https://registry.npmjs.org/example/-/example-1.2.3.tgz"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
with self.assertRaisesRegex(ValueError, "no verified duplicate"):
|
||||||
|
complete_lock(path)
|
||||||
|
|
||||||
|
def test_rejects_conflicting_integrities_for_same_url(self):
|
||||||
|
url = "https://registry.npmjs.org/example/-/example-1.2.3.tgz"
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
path = self._lock(directory, {
|
||||||
|
"node_modules/a": {"resolved": url, "integrity": "sha512-a"},
|
||||||
|
"node_modules/b": {"resolved": url, "integrity": "sha512-b"},
|
||||||
|
})
|
||||||
|
with self.assertRaisesRegex(ValueError, "conflicting integrity"):
|
||||||
|
complete_lock(path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user