ci/woodpecker/push/publish Pipeline was successful
Co-authored-by: marcie <[email protected]>
65 lines
2.6 KiB
Python
Executable File
65 lines
2.6 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# git-credential-mosaic — production entrypoint (P0-SEC R4, rev-code-02 B1).
|
|
#
|
|
# WHY THIS IS NOT BASH: three review rounds falsified every in-bash startup
|
|
# guard. A non-interactive bash sources $BASH_ENV and imports exported
|
|
# functions BEFORE the first script line, so read(), unset(), exit(),
|
|
# declare(), printf() — every callable — can be shadows that fake the
|
|
# ancestry, defeat the scrub, or forge diagnostics (rev-code-02 probes 1 and
|
|
# 2, artifacts fc49e9d9 lineage). No in-language dispatch survives that.
|
|
#
|
|
# This entrypoint is unshapable at the bash level: python does not read
|
|
# BASH_ENV and imports no bash functions, and the interpreter is pinned by
|
|
# absolute shebang (no PATH resolution). It builds the child environment BY
|
|
# ALLOWLIST and execve's the bash implementation directly — the child bash
|
|
# starts with no BASH_ENV, no BASH_FUNC_*, no SHELLOPTS/BASHOPTS, and exactly
|
|
# the variables the credential protocol needs. stdin/stdout/stderr and argv
|
|
# pass through untouched.
|
|
#
|
|
# The implementation file (git-credential-mosaic.impl) refuses to run without
|
|
# the clean-mode marker, so it cannot be invoked directly as a shaped-entry
|
|
# bypass of this wrapper.
|
|
|
|
import os
|
|
import sys
|
|
|
|
IMPL = os.path.join(os.path.dirname(os.path.realpath(__file__)), "git-credential-mosaic.impl")
|
|
# Absolute-path candidates ONLY — never PATH resolution (an attacker-shaped
|
|
# PATH must not choose the interpreter). /usr/bin/bash is the fleet-host
|
|
# layout; /bin/bash is alpine and other FHS variants (found by the T125
|
|
# gateway-image verification: the hardcoded /usr/bin/bash made every call
|
|
# exit 127 inside node:22-alpine).
|
|
BASH_CANDIDATES = ("/usr/bin/bash", "/bin/bash")
|
|
BASH = next((p for p in BASH_CANDIDATES if os.access(p, os.X_OK)), None)
|
|
|
|
# Allowlist: everything else in the environment dies at this boundary. Adding
|
|
# a variable here is a security decision — it crosses into a shell that no
|
|
# longer has any startup shaping, but it also becomes the only context the
|
|
# implementation can see.
|
|
KEEP = (
|
|
"HOME",
|
|
"PATH",
|
|
"LANG",
|
|
"MOSAIC_GIT_IDENTITY",
|
|
"MOSAIC_AGENT_NAME",
|
|
"MOSAIC_BRAIN_HOME",
|
|
"MOSAIC_CREDENTIAL_SPOOL",
|
|
"MOSAIC_CREDENTIAL_LINEAGE_FENCE",
|
|
)
|
|
|
|
env = {"_MOSAIC_HELPER_CLEAN": "1"}
|
|
for name in KEEP:
|
|
value = os.environ.get(name)
|
|
if value is not None:
|
|
env[name] = value
|
|
|
|
argv = [BASH, IMPL] + sys.argv[1:]
|
|
if BASH is None:
|
|
sys.stderr.write("git-credential-mosaic: no executable bash at " + " or ".join(BASH_CANDIDATES) + "\n")
|
|
sys.exit(127)
|
|
try:
|
|
os.execve(BASH, argv, env)
|
|
except OSError as exc:
|
|
sys.stderr.write(f"git-credential-mosaic: entrypoint exec failed: {exc}\n")
|
|
sys.exit(127)
|