A package is one bounded JSON manifest, never an archive or executable.
POSIX descriptor-relative reads reject symlinks in every path component. Digest
identifies validated manifest data, not provenance, signatures or approval.
MAX_MANIFEST_BYTES
module-attribute
MAX_MANIFEST_BYTES = 65536
PackageError
Bases: DoublegateError, ValueError
Fixed diagnostic without paths, keys or content.
Source code in src/doublegate_sdk/package.py
| class PackageError(DoublegateError, ValueError):
"""Fixed diagnostic without paths, keys or content."""
@property
def kind(self):
return str(self.args[0]) if self.args else 'invalid_package'
|
LoadedPackage
dataclass
Source code in src/doublegate_sdk/package.py
| @dataclass(frozen=True, slots=True)
class LoadedPackage:
package: GatePackage
digest: str
|
package
instance-attribute
digest
instance-attribute
read_bounded
read_bounded(path: str | Path, limit: int) -> bytes
Read a regular file once; no symlinks, special files or unbounded reads.
Source code in src/doublegate_sdk/package.py
| def read_bounded(path: str | Path, limit: int) -> bytes:
"""Read a regular file once; no symlinks, special files or unbounded reads."""
fd = None
parent = None
try:
parts = Path(path).parts
if not parts or '..' in parts:
raise PackageError('unsafe_path')
flags = os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK
parent = os.open('/' if Path(path).is_absolute() else '.', flags | os.O_DIRECTORY)
names = parts[1:] if Path(path).is_absolute() else parts
if not names:
raise PackageError('not_regular_file')
for name in names[:-1]:
child = os.open(name, flags | os.O_DIRECTORY, dir_fd=parent)
os.close(parent)
parent = child
fd = os.open(names[-1], flags, dir_fd=parent)
info = os.fstat(fd)
if not stat.S_ISREG(info.st_mode):
raise PackageError('not_regular_file')
if info.st_size > limit:
raise PackageError('file_too_large')
with os.fdopen(fd, 'rb') as stream:
fd = None
data = stream.read(limit + 1)
if len(data) > limit:
raise PackageError('file_too_large')
return data
except (OSError, ValueError) as error:
if isinstance(error, PackageError):
raise
raise PackageError('unreadable_file') from None
finally:
if fd is not None:
os.close(fd)
if parent is not None:
os.close(parent)
|
load_package
load_package(path: str | Path) -> LoadedPackage
Hash sorted, compact, ASCII-escaped JSON after strict manifest validation.
Source code in src/doublegate_sdk/package.py
| def load_package(path: str | Path) -> LoadedPackage:
"""Hash sorted, compact, ASCII-escaped JSON after strict manifest validation."""
data = read_bounded(path, MAX_MANIFEST_BYTES)
try:
raw = json.loads(data.decode('utf-8'), object_pairs_hook=_unique_object)
except (ValueError, RecursionError):
raise PackageError('invalid_json') from None
package = validate_manifest(raw)
canonical = json.dumps(raw, sort_keys=True, separators=(',', ':'), ensure_ascii=True)
return LoadedPackage(package, hashlib.sha256(canonical.encode('ascii')).hexdigest())
|