Skip to content

Commit

Permalink
feat(back): fluidattacks#894 generate provenance
Browse files Browse the repository at this point in the history
- Generate the fields that are easy to generate
  from the information we have
  • Loading branch information
kamadorueda committed Sep 6, 2022
1 parent 4c3a326 commit 93998ae
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 0 deletions.
1 change: 1 addition & 0 deletions makes.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
bin = [inputs.nixpkgs.hello];
};
makes = {
bin = [inputs.nixpkgs.just];
source = [outputs."/cli/pypi"];
};
};
Expand Down
101 changes: 101 additions & 0 deletions src/cli/main/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from os import (
environ,
getcwd,
getlogin,
makedirs,
remove,
)
Expand All @@ -33,6 +34,9 @@
import rich.text
import shlex
import shutil
from socket import (
gethostname,
)
import subprocess # nosec
import sys
import tempfile
Expand Down Expand Up @@ -249,6 +253,15 @@ def _clone_src_git_init(head: str) -> None:
raise SystemExit(out)


def _clone_src_git_rev_parse(head: str, rev: str) -> str:
cmd = ["git", "-C", head, "rev-parse", rev]
out, stdout, _ = _run_outputs(cmd, stderr=None)
if out != 0:
raise SystemExit(out)

return next(iter(stdout.decode().splitlines()), "HEAD")


def _clone_src_git_fetch(head: str, remote: str, rev: str) -> None:
depth = _if(GIT_DEPTH >= 1, f"--depth={GIT_DEPTH}")
cmd = ["git", "-C", head, "fetch", *depth, remote, f"{rev}:{rev}"]
Expand Down Expand Up @@ -378,6 +391,45 @@ def _nix_build(
]


def _nix_hashes(*paths: str) -> List[str]:
cmd = [
f"{__NIX_STABLE__}/bin/nix-store",
"--query",
"--hash",
*paths,
]
out, stdout, _ = _run_outputs(cmd, stderr=None)
if out != 0:
raise SystemExit(out)

return stdout.decode().splitlines()


def _nix_build_requisites(path: str) -> List[Tuple[str, str]]:
"""Answer the question: what do I need to build `out`."""
cmd = [f"{__NIX_STABLE__}/bin/nix-store", "--query", "--deriver", path]
out, stdout, _ = _run_outputs(cmd, stderr=None)
if out != 0:
raise SystemExit(out)

cmd = [
f"{__NIX_STABLE__}/bin/nix-store",
"--query",
"--requisites",
"--include-outputs",
*stdout.decode().splitlines(),
]
out, stdout, _ = _run_outputs(cmd, stderr=None)
if out != 0:
raise SystemExit(out)

requisites: List[str] = stdout.decode().splitlines()

hashes: List[str] = _nix_hashes(*requisites)

return list(zip(requisites, hashes))


def _get_head(src: str) -> str:
# Checkout repository HEAD into a temporary directory
# This is nice for reproducibility and security,
Expand Down Expand Up @@ -798,7 +850,10 @@ def cli(args: List[str]) -> None:
stderr=None,
stdout=None,
)
provenance: str = join(MAKES_DIR, f"provenance{attr.replace('/', '-')}")

if code == 0:
write_provenance(args[2:], head, out, provenance, src)
cache_push(cache, out)
execute_action(args[3:], head, out)
raise SystemExit(code)
Expand Down Expand Up @@ -832,6 +887,52 @@ def cache_push(cache: List[Dict[str, str]], out: str) -> None:
return


def write_provenance(
args: List[str], head: str, out: str, provenance: str, src: str
) -> None:
attestation: Dict[str, Any] = {}
attestation["_type"] = "https://in-toto.io/Statement/v0.1"
attestation["predicateType"] = "https://slsa.dev/provenance/v0.2"

attestation["predicate"] = {}
attestation["predicate"]["builder"] = {}
attestation["predicate"]["builder"]["id"] = f"{getlogin()}@{gethostname()}"
attestation["predicate"]["buildType"] = (
f"https://fluidattacks.com/Attestations/Makes@{VERSION}",
)
attestation["predicate"]["invocation"] = {}
attestation["predicate"]["invocation"]["configSource"] = {
"uri": f"git+https://{src}",
"digest": {"sha1": _clone_src_git_rev_parse(head, "HEAD")},
"entrypoint": args[0],
}
attestation["predicate"]["invocation"]["parameters"] = args[1:]
attestation["predicate"]["metadata"] = {}
attestation["predicate"]["metadata"]["completeness"] = {}
attestation["predicate"]["metadata"]["completeness"]["environment"] = False
attestation["predicate"]["metadata"]["completeness"]["materials"] = True
attestation["predicate"]["metadata"]["completeness"]["parameters"] = True
attestation["predicate"]["materials"] = []
for requisite, hash_ in _nix_build_requisites(out):
attestation["predicate"]["materials"].append(
{
"uri": requisite,
"hash": dict([hash_.split(":")]), # type: ignore
}
)

attestation["subject"] = []
attestation["subject"].append(
{
"uri": out,
"hash": dict([_nix_hashes(out)[0].split(":")]), # type: ignore
}
)

with open(provenance, encoding="utf-8", mode="w+") as attestation_file:
json.dump(attestation, attestation_file, indent=2, sort_keys=True)


def main() -> None:
try:
cli(sys.argv)
Expand Down

0 comments on commit 93998ae

Please sign in to comment.