Remediate RC6 container scan findings
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-18 04:28:46 +02:00
parent 027e4b078b
commit 6a22fcd1f8
8 changed files with 65 additions and 2 deletions
+14
View File
@@ -101,4 +101,18 @@ def test_release_image_uses_locked_non_ai_dependencies_and_npm_ci() -> None:
assert "pip install --no-cache-dir --require-hashes -r requirements-runtime.lock" in dockerfile
assert "ARG GEOINTEL_ULTRALYTICS_VERSION=8.4.99" in dockerfile
assert '"ultralytics==$GEOINTEL_ULTRALYTICS_VERSION"' in dockerfile
assert "ARG GEOINTEL_SETUPTOOLS_VERSION=83.0.0" in dockerfile
assert "ARG GEOINTEL_WHEEL_VERSION=0.47.0" in dockerfile
assert "COPY deploy/unraid/gosu-setpriv /usr/local/bin/gosu" in dockerfile
assert "&& pip check" in dockerfile
def test_gosu_compatibility_wrapper_uses_exec_and_setpriv() -> None:
wrapper = read("deploy/unraid/gosu-setpriv")
readiness = read("scripts/run_readiness_check.sh")
assert "exec setpriv" in wrapper
assert '--reuid="$target_user"' in wrapper
assert '--regid="$target_user"' in wrapper
assert "--init-groups" in wrapper
assert "bash -n deploy/unraid/gosu-setpriv" in readiness
+7 -1
View File
@@ -13,6 +13,8 @@ ARG GEOINTEL_TORCH_INDEX_URL=https://download.pytorch.org/whl/cpu
ARG GEOINTEL_TORCH_VERSION=2.13.0
ARG GEOINTEL_TORCHVISION_VERSION=0.28.0
ARG GEOINTEL_ULTRALYTICS_VERSION=8.4.99
ARG GEOINTEL_SETUPTOOLS_VERSION=83.0.0
ARG GEOINTEL_WHEEL_VERSION=0.47.0
ENV GEOINTEL_ENV=production \
GEOINTEL_API_PREFIX=/api/v1 \
@@ -48,6 +50,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /app
COPY deploy/unraid/gosu-setpriv /usr/local/bin/gosu
COPY backend/pyproject.toml /app/
COPY backend/requirements-runtime.lock /app/
COPY backend/app/__init__.py /app/app/__init__.py
@@ -63,6 +66,9 @@ RUN printf '# GeoIntel backend package metadata\n' > /app/README.md \
&& pip install --no-cache-dir \
"ultralytics==$GEOINTEL_ULTRALYTICS_VERSION"; \
fi \
&& pip install --no-cache-dir \
"setuptools==$GEOINTEL_SETUPTOOLS_VERSION" \
"wheel==$GEOINTEL_WHEEL_VERSION" \
&& pip check
COPY backend/ /app/
@@ -139,7 +145,7 @@ COPY deploy/unraid/nginx-all-in-one.conf /etc/nginx/conf.d/default.conf
COPY deploy/unraid/all-in-one-start.sh /usr/local/bin/geointel-all-in-one-start
COPY --from=frontend-build /frontend/dist/ /usr/share/nginx/html/
RUN chmod +x /usr/local/bin/geointel-all-in-one-start \
RUN chmod +x /usr/local/bin/geointel-all-in-one-start /usr/local/bin/gosu \
&& chmod +x \
/app/scripts/train_operator_yolo_detector.sh \
/app/scripts/verify_real_data_detection_qa_workflow.sh \
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
set -eu
if [ "$#" -lt 2 ]; then
echo "usage: gosu user command [args...]" >&2
exit 64
fi
target_user="$1"
shift
exec setpriv \
--reuid="$target_user" \
--regid="$target_user" \
--init-groups \
"$@"
+4 -1
View File
@@ -73,12 +73,15 @@ The dependency job:
- publishes both unfiltered and policy-filtered Python JSON reports plus the
npm JSON report, including on failure.
The only current Python exceptions are the Starlette 2026 advisories recorded
The only current Python/container exceptions are the Starlette 2026 advisories recorded
in `security/pip-audit-exceptions.json`. FastAPI 0.139.2 still constrains
Starlette below 0.53 while patched releases begin at 1.x. GeoIntel applies
request-target, form-content, route-class and Linux-runtime compensating
controls. The exception file has a mandatory review date; readiness and CI
fail automatically after it expires. New advisories are never auto-ignored.
The all-in-one image replaces the Go-based base-image `gosu` helper with a
small `setpriv` exec wrapper and upgrades packaged setuptools/wheel metadata;
these scanner findings are fixed rather than excepted.
The container job builds a non-AI all-in-one image and uses digest-pinned
scanner images:
+1
View File
@@ -118,6 +118,7 @@ bash -n scripts/deploy_tower.sh
bash -n scripts/verify_release_fresh_install.sh
bash -n scripts/verify_release_upgrade_smoke.sh
bash -n deploy/unraid/all-in-one-start.sh
bash -n deploy/unraid/gosu-setpriv
bash -n deploy/unraid/run-dockerman-container.sh
bash -n deploy/unraid/deploy-release.sh
bash -n deploy/unraid/rollback-dockerman-container.sh
+7
View File
@@ -6,6 +6,9 @@ TARGET_IMAGE="${1:-geointel-ci:local}"
OUTPUT="${2:-artifacts/geointel-container-vulnerabilities.json}"
TRIVY_IMAGE="aquasec/trivy:0.70.0@sha256:be1190afcb28352bfddc4ddeb71470835d16462af68d310f9f4bca710961a41e"
CACHE_DIR="${GEOINTEL_TRIVY_CACHE:-$ROOT/.cache/trivy}"
PYTHON_CMD="${PYTHON_BIN:-python3}"
IGNORE_FILE="$(mktemp)"
trap 'rm -f "$IGNORE_FILE"' EXIT
case "$OUTPUT" in
/*|*..*)
@@ -16,6 +19,9 @@ esac
docker image inspect "$TARGET_IMAGE" >/dev/null
mkdir -p "$ROOT/$(dirname "$OUTPUT")" "$CACHE_DIR"
"$PYTHON_CMD" "$ROOT/scripts/verify_security_exceptions.py"
"$PYTHON_CMD" "$ROOT/scripts/verify_security_exceptions.py" \
--print-container-ids > "$IGNORE_FILE"
# Keep the complete report, including vulnerabilities without an available fix.
docker run --rm \
@@ -42,6 +48,7 @@ docker run --rm \
--timeout 20m \
--skip-version-check \
--ignore-unfixed \
--ignorefile "$IGNORE_FILE" \
--severity HIGH,CRITICAL \
--exit-code 1 \
"$TARGET_IMAGE"
+15
View File
@@ -40,12 +40,23 @@ def load_and_validate() -> tuple[dict[str, object], list[str]]:
if not isinstance(item, dict) or len(str(item.get("reason", ""))) < 30:
errors.append("every advisory requires a specific reason")
break
aliases = [
str(alias)
for item in advisories
if isinstance(item, dict)
for alias in item.get("aliases", [])
]
if len(aliases) != len(set(aliases)) or any(
not alias.startswith("CVE-") for alias in aliases
):
errors.append("container aliases must be unique CVE identifiers")
return payload, errors
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--print-ids", action="store_true")
parser.add_argument("--print-container-ids", action="store_true")
args = parser.parse_args()
payload, errors = load_and_validate()
if errors:
@@ -55,6 +66,10 @@ def main() -> int:
if args.print_ids:
for item in payload["advisories"]:
print(item["id"])
elif args.print_container_ids:
for item in payload["advisories"]:
for alias in item.get("aliases", []):
print(alias)
else:
print(
"Dependency exceptions valid through "
+2
View File
@@ -19,6 +19,7 @@
},
{
"id": "PYSEC-2026-249",
"aliases": ["CVE-2026-54283"],
"reason": "GeoIntel rejects application/x-www-form-urlencoded before Starlette form parsing."
},
{
@@ -27,6 +28,7 @@
},
{
"id": "PYSEC-2026-2281",
"aliases": ["CVE-2026-48818"],
"reason": "The supported all-in-one production runtime is Linux; the advisory affects Windows StaticFiles."
}
]