fix(release): make deployment backup and rollback immutable
This commit is contained in:
@@ -17,29 +17,39 @@ EXCEPTIONS_PATH = ROOT / "security" / "pip-audit-exceptions.json"
|
||||
def load_and_validate() -> tuple[dict[str, object], list[str]]:
|
||||
payload = json.loads(EXCEPTIONS_PATH.read_text(encoding="utf-8"))
|
||||
errors: list[str] = []
|
||||
try:
|
||||
review_by = dt.date.fromisoformat(str(payload["review_by"]))
|
||||
except (KeyError, ValueError):
|
||||
errors.append("review_by must be an ISO date")
|
||||
review_by = dt.date.min
|
||||
if review_by < dt.date.today():
|
||||
errors.append(f"dependency exception review expired on {review_by.isoformat()}")
|
||||
if payload.get("package") != "starlette":
|
||||
errors.append("only the documented Starlette compatibility exception is allowed")
|
||||
controls = payload.get("compensating_controls")
|
||||
if not isinstance(controls, list) or len(controls) < 3:
|
||||
errors.append("at least three compensating controls are required")
|
||||
if set(payload) != {"schema_version", "advisories"}:
|
||||
errors.append("exception policy must contain only schema_version and advisories")
|
||||
if payload.get("schema_version") != 1:
|
||||
errors.append("schema_version must be 1")
|
||||
advisories = payload.get("advisories")
|
||||
if not isinstance(advisories, list) or not advisories:
|
||||
errors.append("at least one advisory exception is required")
|
||||
if not isinstance(advisories, list):
|
||||
errors.append("advisories must be a list")
|
||||
else:
|
||||
ids = [str(item.get("id", "")) for item in advisories if isinstance(item, dict)]
|
||||
if len(ids) != len(set(ids)) or any(not item.startswith("PYSEC-") for item in ids):
|
||||
errors.append("advisory IDs must be unique PYSEC identifiers")
|
||||
for item in advisories:
|
||||
if not isinstance(item, dict) or len(str(item.get("reason", ""))) < 30:
|
||||
if not isinstance(item, dict):
|
||||
errors.append("every advisory must be an object")
|
||||
continue
|
||||
required = {"id", "package", "review_by", "reason"}
|
||||
allowed = required | {"aliases"}
|
||||
if not required.issubset(item) or not set(item).issubset(allowed):
|
||||
errors.append("every advisory must match the documented exception schema")
|
||||
if not str(item.get("package", "")).strip():
|
||||
errors.append("every advisory requires a package")
|
||||
if len(str(item.get("reason", ""))) < 30:
|
||||
errors.append("every advisory requires a specific reason")
|
||||
break
|
||||
try:
|
||||
review_by = dt.date.fromisoformat(str(item["review_by"]))
|
||||
except (KeyError, ValueError):
|
||||
errors.append("every advisory review_by must be an ISO date")
|
||||
else:
|
||||
if review_by < dt.date.today():
|
||||
errors.append(
|
||||
f"dependency exception {item.get('id', '')} expired on "
|
||||
f"{review_by.isoformat()}"
|
||||
)
|
||||
aliases = [
|
||||
str(alias)
|
||||
for item in advisories
|
||||
@@ -72,8 +82,7 @@ def main() -> int:
|
||||
print(alias)
|
||||
else:
|
||||
print(
|
||||
"Dependency exceptions valid through "
|
||||
f"{payload['review_by']} with documented compensating controls."
|
||||
f"Dependency exception policy valid; {len(payload['advisories'])} active exception(s)."
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user