diff --git a/skootrs-lib/src/service/facet.rs b/skootrs-lib/src/service/facet.rs index ca6889d..78443f6 100644 --- a/skootrs-lib/src/service/facet.rs +++ b/skootrs-lib/src/service/facet.rs @@ -543,6 +543,11 @@ impl SourceBundleContentGenerator for GoGithubSourceBundleContentHandler { ) -> Result { match params.facet_type { SupportedFacetType::Gitignore => self.generate_gitignore_content(params), + // TODO: Rename this to something like SecureBuild. + // This also does a bunch of other stuff like setting up releases, generating SBOM, etc. + // So for now just we just use it instead of creating multiple facets. + // The better option is to probably set up some mapping of properties like SLSA, SBOMGenerating, etc. + // to a single SecureBuild facet. SupportedFacetType::SLSABuild => self.generate_slsa_build_content(params), SupportedFacetType::DependencyUpdateTool => { self.generate_dependency_update_tool_content(params) @@ -581,21 +586,55 @@ impl GoGithubSourceBundleContentHandler { // Note: Content mostly taken from https://github.com/guacsec/guac/blob/f1703bd4ca3c0ec0fa55c5a3401d50578fb1680e/.github/workflows/release.yaml fn generate_slsa_build_content( &self, - _params: &SourceBundleFacetParams, + params: &SourceBundleFacetParams, ) -> Result { // TODO: This should really be a struct that serializes to yaml instead of just a file template #[derive(Template)] #[template(path = "go.releases.yml", escape = "none")] - struct SLSABuildTemplateParams {} + struct ReleaseTemplateParams {} + + #[derive(Template)] + #[template(path = "Dockerfile.goreleaser", escape = "none")] + struct DockerfileTemplateParams { + project_name: String, + } - let slsa_build_template_params = SLSABuildTemplateParams {}; - let content = slsa_build_template_params.render()?; + #[derive(Template)] + #[template(path = "goreleaser.yml", escape = "none")] + struct GoReleaserTemplateParams { + project_name: String, + module_name: String, + } + + let module = match ¶ms.common.ecosystem { + InitializedEcosystem::Go(go) => go.module(), + _ => unreachable!("Ecosystem should be Go"), + }; + + let slsa_build_template_params = ReleaseTemplateParams {}; + let dockerfile_template_params = DockerfileTemplateParams { + project_name: params.common.project_name.clone(), + }; + let goreleaser_template_params = GoReleaserTemplateParams { + project_name: params.common.project_name.clone(), + module_name: module, + }; Ok(SourceBundleContent { source_files_content: vec![SourceFileContent { name: "releases.yml".to_string(), path: ".github/workflows/".to_string(), - content, + content: slsa_build_template_params.render()?, + }, + SourceFileContent { + name: "Dockerfile.goreleaser".to_string(), + path: "./".to_string(), + content: dockerfile_template_params.render()?, + }, + SourceFileContent { + name: ".goreleaser.yml".to_string(), + path: "./".to_string(), + content: goreleaser_template_params.render()?, }], facet_type: SupportedFacetType::SLSABuild, }) @@ -726,7 +765,7 @@ impl FacetSetParamsGenerator { common_params: &CommonFacetParams, ) -> Result { use SupportedFacetType::{ - DefaultSourceCode, DependencyUpdateTool, Fuzzing, Gitignore, License, Readme, + DefaultSourceCode, DependencyUpdateTool, Gitignore, License, Readme, SLSABuild, Scorecard, SecurityInsights, SecurityPolicy, SAST, }; let supported_facets = [ @@ -739,7 +778,9 @@ impl FacetSetParamsGenerator { // SBOMGenerator, // Handled by the SLSABuild facet // StaticCodeAnalysis, DependencyUpdateTool, - Fuzzing, + // TODO: Fuzzing right now requires a bunch of resources that are unavailable to most projects without + // some sort of manual intervention. This is disabled until some option becomes available. + // Fuzzing, Scorecard, // PublishPackages, // PinnedDependencies, diff --git a/skootrs-lib/templates/Dockerfile.goreleaser b/skootrs-lib/templates/Dockerfile.goreleaser new file mode 100644 index 0000000..f1ad0a3 --- /dev/null +++ b/skootrs-lib/templates/Dockerfile.goreleaser @@ -0,0 +1,8 @@ +FROM --platform=$BUILDPLATFORM alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b as certs +RUN apk --update add ca-certificates + +FROM --platform=$BUILDPLATFORM alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b +COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +RUN apk --update --no-cache add wget && rm -rf /var/cache/apk/* + +workdir /{{ project_name }} \ No newline at end of file diff --git a/skootrs-lib/templates/go.releases.yml b/skootrs-lib/templates/go.releases.yml index c4f17e3..86ae52a 100644 --- a/skootrs-lib/templates/go.releases.yml +++ b/skootrs-lib/templates/go.releases.yml @@ -1,4 +1,5 @@ {% raw %} + # # Copyright 2022 The GUAC Authors. # @@ -107,6 +108,9 @@ jobs: sbom-container: # generate sbom for container as goreleaser can't - https://goreleaser.com/customization/sbom/#limitations + permissions: + id-token: write + packages: write name: generate sbom for container runs-on: ubuntu-latest needs: [goreleaser] @@ -132,8 +136,7 @@ jobs: run: | #!/usr/bin/env bash set -euo pipefail - cosign attach sbom --sbom spdx.sbom.json ${IMAGE_URI_DIGEST} - cosign sign -a git_sha=$GITHUB_SHA --attachment sbom ${IMAGE_URI_DIGEST} --yes + cosign attest --predicate spdx.sbom.json ${IMAGE_URI_DIGEST} --yes shell: bash env: IMAGE_URI_DIGEST: ${{ needs.goreleaser.outputs.image }}@${{ needs.goreleaser.outputs.digest }} diff --git a/skootrs-lib/templates/goreleaser.yml b/skootrs-lib/templates/goreleaser.yml new file mode 100644 index 0000000..4360ac5 --- /dev/null +++ b/skootrs-lib/templates/goreleaser.yml @@ -0,0 +1,137 @@ +--- +project_name: {{ project_name }} + + +env: + - CGO_ENABLED=0 + - PKG={{ module_name }} +{% raw %} + +dockers: + # see details at https://goreleaser.com/customization/docker/ + - use: buildx + goos: linux + goarch: amd64 + image_templates: + - "ghcr.io/{{ .Env.GITHUB_REPOSITORY }}:{{ .Tag }}-amd64" + dockerfile: Dockerfile.goreleaser + build_flag_templates: + - "--platform=linux/amd64" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.name={{.ProjectName}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.source={{.GitURL}}" + - "--builder={{ .Env.DOCKER_CONTEXT }}" + - use: buildx + goos: linux + goarch: arm64 + image_templates: + - "ghcr.io/{{ .Env.GITHUB_REPOSITORY }}:{{ .Tag }}-arm64" + dockerfile: Dockerfile.goreleaser + build_flag_templates: + - "--platform=linux/arm64" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.name={{.ProjectName}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.source={{.GitURL}}" + - "--builder={{ .Env.DOCKER_CONTEXT }}" + +docker_manifests: + - name_template: "ghcr.io/{{ .Env.GITHUB_REPOSITORY }}:{{ .Tag }}" + image_templates: + - "ghcr.io/{{ .Env.GITHUB_REPOSITORY }}:{{ .Tag }}-amd64" + - "ghcr.io/{{ .Env.GITHUB_REPOSITORY }}:{{ .Tag }}-arm64" + +docker_signs: + - cmd: cosign + artifacts: all + output: true + args: + - "sign" + - "--a" + - "git_sha={{.FullCommit}}" + - "ghcr.io/{{ .Env.GITHUB_REPOSITORY }}@${digest}" + - "--yes" + +before: + hooks: + - go mod tidy + - go generate ./... + +builds: + - main: ./ + id: main + binary: main-{{ .Os }}-{{ .Arch }} + ldflags: + # See https://goreleaser.com/customization/templates/#common-fields for field definitions + - -X {{.Env.PKG}}.Commit={{.FullCommit}} + - -X {{.Env.PKG}}.Date={{.Date}} + - -X {{.Env.PKG}}.Version={{.Summary}} + goos: [ 'darwin', 'linux', 'windows' ] + goarch: + - amd64 + - arm64 + - arm + ignore: + - goos: windows + goarch: arm64 + - goos: windows + goarch: arm + +universal_binaries: + - replace: true + name_template: main + id: main + ids: + - main + +sboms: + - id: bins + artifacts: binary + documents: + - "${artifact}.spdx.sbom.json" + +signs: + - id: cosign-keyless + artifacts: checksum + signature: "${artifact}-keyless.sig" + certificate: "${artifact}-keyless.pem" + cmd: cosign + args: + - "sign-blob" + - "--yes" + - "--output-signature" + - "${artifact}-keyless.sig" + - "--output-certificate" + - "${artifact}-keyless.pem" + - "${artifact}" + output: true + +archives: + - format: binary + name_template: "{{ .Binary }}" + allow_different_binary_count: true + +checksum: + name_template: "{{ .ProjectName }}_checksums.txt" + +snapshot: + name_template: SNAPSHOT-{{ .ShortCommit }} + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + +release: + prerelease: auto + draft: false + replace_existing_draft: true +# The lines beneath this are called `modelines`. See `:help modeline` +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj +{% endraw %} \ No newline at end of file