CC: add Vision package Docker context
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
.git
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.ruff_cache
|
||||
.venv
|
||||
__pycache__
|
||||
*.pyc
|
||||
outputs
|
||||
worktrees
|
||||
tests
|
||||
docs
|
||||
candidate-manifests
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
SVRNTY_VISION_HOST=0.0.0.0 \
|
||||
SVRNTY_VISION_PORT=8094
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN useradd --create-home --shell /usr/sbin/nologin vision
|
||||
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY src ./src
|
||||
|
||||
RUN python -m pip install --no-cache-dir --upgrade pip \
|
||||
&& python -m pip install --no-cache-dir .
|
||||
|
||||
USER vision
|
||||
|
||||
EXPOSE 8094
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8094/healthz', timeout=3).read()"
|
||||
|
||||
CMD ["python", "-m", "svrnty_vision.server"]
|
||||
@@ -14,3 +14,8 @@ items:
|
||||
status: ready-for-agent
|
||||
source: outputs/sandcastle-vision-package-candidate/README.md
|
||||
owner: jp
|
||||
- id: SVRNTY-VISION-WORK-004
|
||||
title: Package Docker Build Context
|
||||
status: complete
|
||||
source: Dockerfile
|
||||
owner: jp
|
||||
|
||||
@@ -19,12 +19,16 @@ REQUIRED = [
|
||||
"candidate-manifests/vision-package-candidate.json",
|
||||
"candidate-manifests/vision-tool-grants.json",
|
||||
"candidate-manifests/visual-evidence-contract.json",
|
||||
"Dockerfile",
|
||||
".dockerignore",
|
||||
"tools/validate_vision_package_docker_context.py",
|
||||
]
|
||||
VALIDATORS = [
|
||||
"tools/validate_vision_package_candidate.py",
|
||||
"tools/validate_vision_tool_grants.py",
|
||||
"tools/validate_visual_evidence_contract.py",
|
||||
"tools/validate_vision_host_adapter_candidates.py",
|
||||
"tools/validate_vision_package_docker_context.py",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate the no-live Vision package Docker build context."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DOCKERFILE = ROOT / "Dockerfile"
|
||||
DOCKERIGNORE = ROOT / ".dockerignore"
|
||||
WORKBOARD = ROOT / "WORKBOARD.yaml"
|
||||
|
||||
REQUIRED_DOCKER_SNIPPETS = [
|
||||
"FROM python:3.12-slim",
|
||||
"SVRNTY_VISION_HOST=0.0.0.0",
|
||||
"SVRNTY_VISION_PORT=8094",
|
||||
"COPY pyproject.toml README.md ./",
|
||||
"COPY src ./src",
|
||||
"python -m pip install --no-cache-dir .",
|
||||
"USER vision",
|
||||
"EXPOSE 8094",
|
||||
"HEALTHCHECK",
|
||||
"http://127.0.0.1:8094/healthz",
|
||||
'CMD ["python", "-m", "svrnty_vision.server"]',
|
||||
]
|
||||
REQUIRED_IGNORE = {
|
||||
".git",
|
||||
".venv",
|
||||
"__pycache__",
|
||||
"outputs",
|
||||
"worktrees",
|
||||
"tests",
|
||||
"candidate-manifests",
|
||||
}
|
||||
FORBIDDEN_PATTERNS = [
|
||||
re.compile(r"sk-[A-Za-z0-9_-]{20,}"),
|
||||
re.compile(r"AIza[0-9A-Za-z_-]{20,}"),
|
||||
re.compile(r"\b(?:ck|cs)_[0-9A-Za-z]{20,}"),
|
||||
re.compile(r"(?i)\b[A-Z0-9_]*(?:PASS|PASSWORD|SECRET|TOKEN|KEY)[A-Z0-9_]*\s*=\s*[^`\s#]{8,}"),
|
||||
]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
errors: list[str] = []
|
||||
dockerfile = DOCKERFILE.read_text(encoding="utf-8") if DOCKERFILE.is_file() else ""
|
||||
dockerignore = DOCKERIGNORE.read_text(encoding="utf-8") if DOCKERIGNORE.is_file() else ""
|
||||
workboard = WORKBOARD.read_text(encoding="utf-8") if WORKBOARD.is_file() else ""
|
||||
if not dockerfile:
|
||||
errors.append("missing:Dockerfile")
|
||||
if not dockerignore:
|
||||
errors.append("missing:.dockerignore")
|
||||
for snippet in REQUIRED_DOCKER_SNIPPETS:
|
||||
if snippet not in dockerfile:
|
||||
errors.append(f"dockerfile_missing:{snippet}")
|
||||
ignore_rows = {line.strip() for line in dockerignore.splitlines() if line.strip() and not line.startswith("#")}
|
||||
for row in sorted(REQUIRED_IGNORE - ignore_rows):
|
||||
errors.append(f"dockerignore_missing:{row}")
|
||||
if "SVRNTY-VISION-WORK-004" not in workboard:
|
||||
errors.append("workboard_missing:SVRNTY-VISION-WORK-004")
|
||||
if "Package Docker Build Context" not in workboard:
|
||||
errors.append("workboard_missing:Package Docker Build Context")
|
||||
combined = "\n".join([dockerfile, dockerignore, workboard])
|
||||
for pattern in FORBIDDEN_PATTERNS:
|
||||
if pattern.search(combined):
|
||||
errors.append(f"value_pattern_found:{pattern.pattern}")
|
||||
result = {
|
||||
"ok": not errors,
|
||||
"validator": "vision-package-docker-context-no-live",
|
||||
"checked": ["Dockerfile", ".dockerignore", "WORKBOARD.yaml"],
|
||||
"errors": errors,
|
||||
"warnings": [],
|
||||
}
|
||||
print(json.dumps(result, indent=2))
|
||||
return 0 if result["ok"] else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user