geenforce: HTTPS payload delivery (content-addressed blob store + endpoint)
Lets share-less (Intune/local-account) PCs pull installers the manifest references over HTTPS instead of SMB - the general capability the whole fleet migrates toward. New ManifestBlob registry (migration 0002) with bytes on disk at instance/geenforce/payloads/<sha256> (deduped by content); service.store_blob + blob_path; client-facing GET /api/geenforce/payload/<sha256> (geenforce.fetch token, ETag=hash, serves the blob store or an inline DB payload by hash). The serializer now emits PayloadSource/PayloadSha256/PayloadRef for http/inline entries only (smb entries round-trip unchanged - parity green). CLI 'flask geenforce add-payload <file>' registers a blob and prints its sha256. This is the shopdb half (B1); the PS client/engine fetch is B2.
This commit is contained in:
@@ -12,13 +12,14 @@ import os
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from flask import current_app
|
||||
from sqlalchemy import func
|
||||
|
||||
from shopdb.api import db, Application
|
||||
|
||||
from .models import (
|
||||
ManifestScope, ManifestPublishedVersion, ManifestEnforcementReport,
|
||||
ManifestEnforcementResult, ManifestPayload,
|
||||
ManifestEnforcementResult, ManifestPayload, ManifestBlob,
|
||||
)
|
||||
from .importer import build_entry
|
||||
from .serializer import scope_to_json
|
||||
@@ -276,6 +277,43 @@ def compliance_for_scope(scope):
|
||||
}
|
||||
|
||||
|
||||
def _payload_dir():
|
||||
d = os.path.join(current_app.instance_path, 'geenforce', 'payloads')
|
||||
os.makedirs(d, exist_ok=True)
|
||||
return d
|
||||
|
||||
|
||||
def blob_path(sha256):
|
||||
"""Filesystem path where a blob's bytes live (may or may not exist)."""
|
||||
return os.path.join(_payload_dir(), sha256)
|
||||
|
||||
|
||||
def store_blob(rawbytes, filename, contenttype=None):
|
||||
"""Store bytes in the content-addressed payload store; return the sha256.
|
||||
|
||||
Deduped by content hash - an already-present blob is not rewritten. Upserts
|
||||
a ManifestBlob registry row (uncommitted). Entries reference it by
|
||||
payloadsha256; the client fetches GET /api/geenforce/payload/<sha256>.
|
||||
"""
|
||||
sha = hashlib.sha256(rawbytes).hexdigest()
|
||||
path = blob_path(sha)
|
||||
if not os.path.exists(path):
|
||||
fd, tmp = tempfile.mkstemp(dir=_payload_dir(), suffix='.tmp')
|
||||
try:
|
||||
with os.fdopen(fd, 'wb') as handle:
|
||||
handle.write(rawbytes)
|
||||
os.replace(tmp, path)
|
||||
except Exception:
|
||||
if os.path.exists(tmp):
|
||||
os.remove(tmp)
|
||||
raise
|
||||
if not db.session.get(ManifestBlob, sha):
|
||||
db.session.add(ManifestBlob(
|
||||
sha256=sha, filename=filename, contenttype=contenttype,
|
||||
sizebytes=len(rawbytes), createdat=_utcnow()))
|
||||
return sha
|
||||
|
||||
|
||||
def store_inline_payload(entry, filename, contenttype, rawbytes):
|
||||
"""Replace the entry's inline payload with these bytes (uncommitted).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user