feat(security): enforce ADR 0005 hosting boundary segregation strictly to family/
This commit is contained in:
@@ -808,17 +808,17 @@ def publish_to_s3(html_content: str, data_dir: Optional[Path] = None) -> str:
|
||||
s3 = get_s3_client()
|
||||
assets_dir = SCRIPT_DIR.parent / "assets"
|
||||
|
||||
# HTML files (both in family/mila.html and mila.html)
|
||||
for key in ["family/mila.html", "mila.html"]:
|
||||
s3.put_object(
|
||||
Bucket=DEFAULT_BUCKET,
|
||||
Key=key,
|
||||
Body=html_content.encode("utf-8"),
|
||||
ContentType="text/html; charset=utf-8",
|
||||
CacheControl="no-cache, no-store, must-revalidate",
|
||||
)
|
||||
# HTML files (strictly under protected family/ path)
|
||||
key = "family/mila.html"
|
||||
s3.put_object(
|
||||
Bucket=DEFAULT_BUCKET,
|
||||
Key=key,
|
||||
Body=html_content.encode("utf-8"),
|
||||
ContentType="text/html; charset=utf-8",
|
||||
CacheControl="no-cache, no-store, must-revalidate",
|
||||
)
|
||||
|
||||
# Static PWA Assets to upload
|
||||
# Static PWA Assets to upload (strictly under family/)
|
||||
static_assets = [
|
||||
("mila.webmanifest", "application/manifest+json; charset=utf-8", "no-cache, no-store, must-revalidate"),
|
||||
("sw.js", "application/javascript; charset=utf-8", "no-cache, no-store, must-revalidate"),
|
||||
@@ -831,24 +831,23 @@ def publish_to_s3(html_content: str, data_dir: Optional[Path] = None) -> str:
|
||||
for fname, ctype, cache_ctrl in static_assets:
|
||||
candidates = [assets_dir / fname]
|
||||
if data_dir:
|
||||
candidates.extend([data_dir.parent / "public" / "family" / fname, data_dir.parent / "public" / fname])
|
||||
candidates.append(data_dir.parent / "public" / "family" / fname)
|
||||
body_bytes = None
|
||||
for candidate in candidates:
|
||||
if candidate.is_file():
|
||||
body_bytes = candidate.read_bytes()
|
||||
break
|
||||
if body_bytes:
|
||||
for prefix in ["family/", ""]:
|
||||
try:
|
||||
s3.put_object(
|
||||
Bucket=DEFAULT_BUCKET,
|
||||
Key=f"{prefix}{fname}",
|
||||
Body=body_bytes,
|
||||
ContentType=ctype,
|
||||
CacheControl=cache_ctrl,
|
||||
)
|
||||
except Exception as ex:
|
||||
print(f"Warning: could not upload {prefix}{fname}: {ex}", file=sys.stderr)
|
||||
try:
|
||||
s3.put_object(
|
||||
Bucket=DEFAULT_BUCKET,
|
||||
Key=f"family/{fname}",
|
||||
Body=body_bytes,
|
||||
ContentType=ctype,
|
||||
CacheControl=cache_ctrl,
|
||||
)
|
||||
except Exception as ex:
|
||||
print(f"Warning: could not upload family/{fname}: {ex}", file=sys.stderr)
|
||||
|
||||
url = f"{DEFAULT_BASE_URL}/family/mila.html"
|
||||
return url
|
||||
@@ -867,21 +866,13 @@ def main():
|
||||
print("Building Mila Dashboard from DuckDB...")
|
||||
html = generate_dashboard_html(engine)
|
||||
|
||||
# 1. Save locally to knowledge-wiki/public/family/mila.html AND public/mila.html
|
||||
# 1. Save locally strictly to knowledge-wiki/public/family/mila.html
|
||||
wiki_public_family = data_dir.parent / "public" / "family"
|
||||
wiki_public_family.mkdir(parents=True, exist_ok=True)
|
||||
out_file = Path(args.output_file) if args.output_file else (wiki_public_family / "mila.html")
|
||||
out_file.write_text(html, encoding="utf-8")
|
||||
print(f"✅ Saved locally: {out_file}")
|
||||
|
||||
# Mirror to public/mila.html
|
||||
root_mila = data_dir.parent / "public" / "mila.html"
|
||||
try:
|
||||
root_mila.write_text(html, encoding="utf-8")
|
||||
print(f"✅ Synced locally: {root_mila}")
|
||||
except Exception as e:
|
||||
print(f"Warning: could not sync to {root_mila}: {e}", file=sys.stderr)
|
||||
|
||||
# 2. Upload to S3 hosting
|
||||
if not args.skip_upload:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user