feat: add agent-os bootstrap bundle

This commit is contained in:
2026-07-02 14:48:49 +00:00
parent d0a9a267fd
commit 5f9302abc5
20 changed files with 715 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/env python3
"""Generate and verify Agent OS bootstrap exports."""
from __future__ import annotations
import argparse
import fnmatch
import json
import shutil
import stat
import sys
from pathlib import Path
BOOTSTRAP_ROOT = Path(__file__).resolve().parent
DEFAULT_OUTPUT = BOOTSTRAP_ROOT / "exports" / "generic"
def load_json(path: Path) -> dict:
with path.open("r", encoding="utf-8") as handle:
return json.load(handle)
def parse_mode(mode: str) -> int:
return int(mode, 8)
def ensure_safe_output(output: Path) -> Path:
resolved = output.resolve()
if resolved.parts[-3:] != ("bootstrap", "exports", "generic"):
raise SystemExit(
"refusing to write outside a bootstrap/exports/generic directory: "
f"{resolved}"
)
return resolved
def copy_file(source: Path, target: Path, mode: str) -> None:
if not source.is_file():
raise FileNotFoundError(f"missing source file: {source}")
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, target)
target.chmod(parse_mode(mode))
def clean_output(output: Path) -> None:
ensure_safe_output(output)
if output.exists():
shutil.rmtree(output)
output.mkdir(parents=True, exist_ok=True)
def create_directories(output: Path, manifest: dict) -> None:
for directory in manifest["directories"]:
target = output / directory["path"]
target.mkdir(parents=True, exist_ok=True)
if directory.get("keep"):
keep_file = target / ".gitkeep"
keep_file.touch()
keep_file.chmod(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
def export_bundle(output: Path, manifest: dict, rules: dict) -> None:
clean_output(output)
create_directories(output, manifest)
for item in rules["metadata"]:
copy_file(
BOOTSTRAP_ROOT / item["source"],
output / item["target"],
item.get("mode", "0644"),
)
template_root = BOOTSTRAP_ROOT / rules["template_root"]
for item in manifest["templates"]:
copy_file(
template_root / item["source"],
output / item["target"],
item.get("mode", "0644"),
)
def verify_required(output: Path, rules: dict) -> list[str]:
failures: list[str] = []
for item in rules["verify"]["required"]:
target = output / item["path"]
expected_type = item["type"]
if expected_type == "file" and not target.is_file():
failures.append(f"missing file: {item['path']}")
elif expected_type == "directory" and not target.is_dir():
failures.append(f"missing directory: {item['path']}")
return failures
def verify_forbidden(output: Path, rules: dict) -> list[str]:
failures: list[str] = []
for path in output.rglob("*"):
rel = path.relative_to(output).as_posix()
for pattern in rules["verify"].get("forbidden", []):
if fnmatch.fnmatch(rel, pattern):
failures.append(f"forbidden path exported: {rel}")
return failures
def verify_export(output: Path, rules: dict) -> None:
failures = verify_required(output, rules) + verify_forbidden(output, rules)
if failures:
for failure in failures:
print(f"FAIL {failure}", file=sys.stderr)
raise SystemExit(1)
def count_files(output: Path) -> int:
return sum(1 for path in output.rglob("*") if path.is_file())
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--output",
type=Path,
default=DEFAULT_OUTPUT,
help="Export directory. Must end in bootstrap/exports/generic.",
)
parser.add_argument(
"--verify-only",
action="store_true",
help="Verify an existing export without regenerating it.",
)
args = parser.parse_args()
output = ensure_safe_output(args.output)
manifest = load_json(BOOTSTRAP_ROOT / "bundle-manifest.json")
rules = load_json(BOOTSTRAP_ROOT / "export-rules.json")
if not args.verify_only:
export_bundle(output, manifest, rules)
verify_export(output, rules)
print(f"OK {manifest['bundle']['id']} -> {output}")
print(f"OK verified {len(rules['verify']['required'])} required paths")
print(f"OK exported {count_files(output)} files")
return 0
if __name__ == "__main__":
raise SystemExit(main())