Skip to content

[CDRIVER-5537] A Signed Release Archive + Augmented SBOM Publication #1637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 11, 2024
Merged
79 changes: 79 additions & 0 deletions Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,85 @@ multibuild:
--c_compiler=gcc --c_compiler=clang \
--test_mongocxx_ref=master

# release-archive :
# Create a release archive of the source tree. (Refer to dev docs)
release-archive:
FROM alpine:3.20
RUN apk add git
ARG --required sbom_branch
ARG --required prefix
ARG --required ref
WORKDIR /s
COPY --dir .git .
COPY (+sbom-download/augmented-sbom.json --branch=$sbom_branch) cyclonedx.sbom.json
RUN git archive -o release.tar.gz \
--verbose \
--prefix="$prefix/" \ # Set the archive path prefix
"$ref" \ # Add the source tree
--add-file cyclonedx.sbom.json # Add the SBOM
SAVE ARTIFACT release.tar.gz

# Obtain the signing public key. Exported as an artifact /c-driver.pub
signing-pubkey:
FROM alpine:3.20
RUN apk add curl
RUN curl --location --silent --fail "https://pgp.mongodb.com/c-driver.pub" -o /c-driver.pub
SAVE ARTIFACT /c-driver.pub

# sign-file :
# Sign an arbitrary file. This uses internal MongoDB tools and requires authentication
# to be used to access them. (Refer to dev docs)
sign-file:
# Pull from Garasign:
FROM artifactory.corp.mongodb.com/release-tools-container-registry-local/garasign-gpg
# Copy the file to be signed
ARG --required file
COPY $file /s/file
# Run the GPG signing command. Requires secrets!
RUN --secret GRS_CONFIG_USER1_USERNAME --secret GRS_CONFIG_USER1_PASSWORD \
gpgloader && \
gpg --yes --verbose --armor --detach-sign --output=/s/signature.asc /s/file
# Export the detatched signature
SAVE ARTIFACT /s/signature.asc /
# Verify the file signature against the public key
COPY +signing-pubkey/c-driver.pub /s/
RUN touch /keyring && \
gpg --no-default-keyring --keyring /keyring --import /s/c-driver.pub && \
gpgv --keyring=/keyring /s/signature.asc /s/file

# signed-release :
# Generate a signed release artifact. Refer to the "Earthly" page of our dev docs for more information.
# (Refer to dev docs)
signed-release:
FROM alpine:3.20
RUN apk add git
# We need to know which branch to get the SBOM from
ARG --required sbom_branch
# The version of the release. This affects the filepaths of the output and is the default for --ref
ARG --required version
# The Git revision of the repository to be archived. By default, archives the tag of the given version
ARG ref=refs/tags/$version
# File stem and archive prefix:
LET stem="mongo-c-driver-$version"
WORKDIR /s
# Run the commands "locally" so that the files can be transferred between the
# targets via the host filesystem.
LOCALLY
# Clean out a scratch space for us to work with
LET rel_dir = ".scratch/release"
RUN rm -rf -- "$rel_dir"
# Primary artifact files
LET rel_tgz = "$rel_dir/$stem.tar.gz"
LET rel_asc = "$rel_dir/$stem.tar.gz.asc"
# Make the release archive:
COPY (+release-archive/release.tar.gz --branch=$sbom_branch --prefix=$stem --ref=$ref) $rel_tgz
# Sign the release archive:
COPY (+sign-file/signature.asc --file $rel_tgz) $rel_asc
# Save them as an artifact.
SAVE ARTIFACT $rel_dir /dist
# Remove our scratch space from the host. Getting at the artifacts requires `earthly --artifact`
RUN rm -rf -- "$rel_dir"

# This target is simply an environment in which the SilkBomb executable is available.
silkbomb:
FROM artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:1.0
Expand Down
63 changes: 63 additions & 0 deletions docs/dev/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

from pathlib import Path
import re
from typing import Callable

from sphinx import addnodes
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment

THIS_FILE = Path(__file__).resolve()
THIS_DIR = THIS_FILE.parent
Expand All @@ -23,6 +29,7 @@
extensions = []
templates_path = []
exclude_patterns = []
default_role = "any"

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
Expand All @@ -35,3 +42,59 @@
.. role:: bash(code)
:language: bash
"""


def annotator(
annot: str,
) -> Callable[[BuildEnvironment, str, addnodes.desc_signature], str]:
"""
Create a parse_node function that adds a parenthesized annotation to an object signature.
"""

def parse_node(
env: BuildEnvironment, sig: str, signode: addnodes.desc_signature
) -> str:
signode += addnodes.desc_name(sig, sig)
signode += addnodes.desc_sig_space()
signode += addnodes.desc_annotation("", f"({annot})")
return sig

return parse_node


def parse_earthly_artifact(
env: BuildEnvironment, sig: str, signode: addnodes.desc_signature
) -> str:
"""
Parse and render the signature of an '.. earthly-artifact::' signature"""
mat = re.match(r"(?P<target>\+.+?)(?P<path>/.*)$", sig)
if not mat:
raise RuntimeError(
f"Invalid earthly-artifact signature: {sig!r} (expected “+<target>/<path> string)"
)
signode += addnodes.desc_addname(mat["target"], mat["target"])
signode += addnodes.desc_name(mat["path"], mat["path"])
signode += addnodes.desc_sig_space()
signode += addnodes.desc_annotation("", "(Earthly Artifact)")
return sig


def setup(app: Sphinx):
app.add_object_type( # type: ignore
"earthly-target",
"earthly-target",
indextemplate="pair: earthly target; %s",
parse_node=annotator("Earthly target"),
)
app.add_object_type( # type: ignore
"script",
"script",
indextemplate="pair: shell script; %s",
parse_node=annotator("shell script"),
)
app.add_object_type( # type: ignore
"earthly-artifact",
"earthly-artifact",
indextemplate="pair: earthly artifact; %s",
parse_node=parse_earthly_artifact,
)
Loading