The live policy keeps the original backup application. Each new key can abort only inside its own prefix. Assistant: grok Assistant-Session: 01a11cdb-f9fe-7011-947c-936e72007e54
98 lines
2.9 KiB
Python
98 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Prove each new publisher can abort its own upload and cannot write elsewhere.
|
|
|
|
No completed object is left behind. The receipt contains status codes only.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import boto3
|
|
from botocore.exceptions import ClientError
|
|
|
|
RECEIPT = Path("/home/worsch/.local/state/railiance/receipts/backup-publisher-prefix-proof.json")
|
|
BUCKET = "railiance-platform-pg-backup"
|
|
PROFILES = {
|
|
"coulomb-social": "platform-pg/application-archives/coulomb-social/.policy-probe",
|
|
"email-connect": "platform-pg/application-archives/email-connect/.policy-probe",
|
|
}
|
|
FOREIGN = "platform-pg/apps-pg/.policy-probe"
|
|
|
|
|
|
def kv(path):
|
|
proc = subprocess.run(["bao", "kv", "get", "-format=json", path], capture_output=True)
|
|
if proc.returncode:
|
|
raise SystemExit(81)
|
|
return json.loads(proc.stdout)["data"]["data"]
|
|
|
|
|
|
def client(values):
|
|
return boto3.client(
|
|
"s3",
|
|
region_name="nl-ams",
|
|
endpoint_url="https://s3.nl-ams.scw.cloud",
|
|
aws_access_key_id=values["AWS_ACCESS_KEY_ID"],
|
|
aws_secret_access_key=values["AWS_SECRET_ACCESS_KEY"],
|
|
)
|
|
|
|
|
|
def code(exc):
|
|
return exc.response.get("Error", {}).get("Code", "error")
|
|
|
|
|
|
def attempt(action):
|
|
try:
|
|
action()
|
|
return "ok"
|
|
except ClientError as exc:
|
|
return code(exc)
|
|
|
|
|
|
def open_or_deny(remote, key):
|
|
try:
|
|
upload = remote.create_multipart_upload(Bucket=BUCKET, Key=key)
|
|
except ClientError as exc:
|
|
return code(exc)
|
|
remote.abort_multipart_upload(Bucket=BUCKET, Key=key, UploadId=upload["UploadId"])
|
|
return "opened_then_aborted"
|
|
|
|
|
|
def main():
|
|
rows = []
|
|
for name, own_key in PROFILES.items():
|
|
remote = client(kv(f"platform/workloads/{name}/backup-primary"))
|
|
own = "error"
|
|
try:
|
|
upload = remote.create_multipart_upload(Bucket=BUCKET, Key=own_key)
|
|
remote.abort_multipart_upload(
|
|
Bucket=BUCKET, Key=own_key, UploadId=upload["UploadId"]
|
|
)
|
|
own = "aborted"
|
|
except ClientError as exc:
|
|
own = code(exc)
|
|
sibling_key = next(key for other, key in PROFILES.items() if other != name)
|
|
foreign = open_or_deny(remote, FOREIGN)
|
|
sibling = open_or_deny(remote, sibling_key)
|
|
delete = attempt(lambda key=own_key: remote.delete_object(Bucket=BUCKET, Key=key))
|
|
rows.append({
|
|
"application": name,
|
|
"own_multipart": own,
|
|
"foreign_multipart": foreign,
|
|
"sibling_multipart": sibling,
|
|
"delete_object": delete,
|
|
})
|
|
RECEIPT.parent.mkdir(mode=0o700, exist_ok=True)
|
|
RECEIPT.write_text(json.dumps({"proofs": rows}, indent=2) + "\n")
|
|
RECEIPT.chmod(0o600)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except SystemExit:
|
|
raise
|
|
except Exception:
|
|
raise SystemExit(82) from None
|