Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

add(intoto, commands, config): more accurate build time #107

Merged
merged 18 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- 'Makefile'

env:
VERSION: v0.3
VERSION: v0.4
IMAGE_NAME: ghcr.io/${{ github.repository }}
COSIGN_VERSION: v1.13.1
SYFT_VERSION: v0.44.1
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/service-account-salsa-integration.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: nais Salsa integration
on:
workflow_run:
workflows: [Salsa build & release]
types: [completed]
branches: [main]
workflows: [ Salsa build & release ]
types: [ completed ]
branches: [ main ]
env:
IMAGE: ttl.sh/nais/salsa-integration-test:1h
jobs:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ The Following inputs can be used as `step.with` keys
| `dependencies` | Bool | true | Set to false if action should not create materials for dependencies (e.g. if build tool is unsupported or repo uses internal/private dependencies) | False |
| `github_token` | String | "" | Token to authenticate and read private packages, the token must have read:packages scope | False |
| `token_key_pattern` | String | "" | If a token is provided but the the key pattern is different from the default key pattern "GITHUB_TOKEN" | False |
| `build_started_on` | String | "" | Specify a workflow build start time | False |
| `repo_dir` | String | $GITHUB_WORKSPACE | **Internal value (do not set):** Root of directory to look for build files | False |
| `github_context` | String | ${{ toJSON(github) }} | **Internal value (do not set):** the [github context](#github-context) object in json | False |
| `runner_context` | String | ${{ toJSON(runner) }} | **Internal value (do not set):** the [runner context](#runner-context) object in json | False |
Expand Down
11 changes: 10 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ inputs:
required: false
default: ${{ github.repository }}

build_started_on:
description: |-
Timestamp of when the build started. Defaults to head commit of workflow,
if provided as input, the timestamp is added to salsa cli flag --build-started-on.
Time format: YYYY-MM-DDTHH:MM:SSZ (RFC3339)
required: false
default: ""

key:
description: |-
The key used to sign the attestation. Cloud Provider KMS key path.
Expand Down Expand Up @@ -89,7 +97,7 @@ inputs:

runs:
using: 'docker'
image: 'docker://ghcr.io/nais/salsa:v0.3'
image: 'docker://ghcr.io/nais/salsa:v0.4'
args:
- ${{ inputs.repo_dir }}
- ${{ inputs.repo_name }}
Expand All @@ -105,3 +113,4 @@ runs:
- ${{ inputs.token_key_pattern }}
- ${{ inputs.docker_pwd }}
- ${{ inputs.dependencies }}
- ${{ inputs.build_started_on }}
1 change: 1 addition & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ scan() {
--env-context "$ENVS" \
--subDir "$INPUT_REPO_SUB_DIR" \
--with-deps="$INPUT_DEPENDENCIES" \
--build-started-on "$INPUT_BUILD_STARTED_ON" \
--remote-run
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/build/jvm/gradle.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"os"
"regexp"
"strings"

Expand Down Expand Up @@ -43,7 +43,7 @@ func (g Gradle) ResolveDeps(workDir string) (*build.ArtifactDependencies, error)
return nil, fmt.Errorf("exec: %v\n", err)
}

xmlData, err := ioutil.ReadFile(workDir + "/gradle/verification-metadata.xml")
xmlData, err := os.ReadFile(workDir + "/gradle/verification-metadata.xml")
if err != nil {
return nil, fmt.Errorf("readfile: %v\n", err)
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/build/jvm/gradle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package jvm
import (
"github.com/nais/salsa/pkg/build"
"github.com/nais/salsa/pkg/build/test"
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGradleDeps(t *testing.T) {
gradleOutput, _ := ioutil.ReadFile("testdata/gradle_output.txt")
checksumXml, _ := ioutil.ReadFile("testdata/verification-metadata.xml")
gradleOutput, _ := os.ReadFile("testdata/gradle_output.txt")
checksumXml, _ := os.ReadFile("testdata/verification-metadata.xml")
got, err := GradleDeps(string(gradleOutput), checksumXml)
assert.NoError(t, err)
want := map[string]build.Dependency{}
Expand Down
3 changes: 1 addition & 2 deletions pkg/build/jvm/mvn.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package jvm
import (
"crypto/sha256"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -86,7 +85,7 @@ func MavenCompileAndRuntimeTimeDeps(rootPath string) (map[string]build.Dependenc
}

func buildChecksum(file string) (build.CheckSum, error) {
content, err := ioutil.ReadFile(file)
content, err := os.ReadFile(file)
if err != nil {
return build.CheckSum{}, err
}
Expand Down
Binary file not shown.
5 changes: 2 additions & 3 deletions pkg/commands/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"github.com/nais/salsa/pkg/dsse"
"github.com/nais/salsa/pkg/intoto"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand All @@ -29,13 +28,13 @@ var findCmd = &cobra.Command{
}

path := PathFlags.RepoDir
dirs, err := ioutil.ReadDir(path)
dirs, err := os.ReadDir(path)
if err != nil {
return fmt.Errorf("could not read dir %w", err)
}

for _, dir := range dirs {
files, err := ioutil.ReadDir(fmt.Sprintf("./%s/%s", path, dir.Name()))
files, err := os.ReadDir(fmt.Sprintf("./%s/%s", path, dir.Name()))
if err != nil {
return fmt.Errorf("could not read dir %w", err)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/commands/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (

type ProvenanceConfig struct {
WithDependencies bool
BuildStartedOn string
}

var scanCmd = &cobra.Command{
Expand Down Expand Up @@ -62,6 +63,7 @@ var scanCmd = &cobra.Command{
}

scanConfiguration := &config.ScanConfiguration{
BuildStartedOn: Config.BuildStartedOn,
WorkDir: workDir,
RepoName: PathFlags.Repo,
Dependencies: deps,
Expand Down Expand Up @@ -116,4 +118,5 @@ func init() {
scanCmd.Flags().StringVar(&runnerContext, "runner-context", "", "context of runner")
scanCmd.Flags().StringVar(&envContext, "env-context", "", "environmental variables of current context")
scanCmd.Flags().BoolVar(&Config.WithDependencies, "with-deps", true, "specify if the cli should generate dependencies for a provenance")
scanCmd.Flags().StringVar(&Config.BuildStartedOn, "build-started-on", "", "set start time for the build")
}
7 changes: 4 additions & 3 deletions pkg/config/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
)

type ScanConfiguration struct {
BuildStartedOn string
Cmd *cobra.Command
ContextEnvironment vcs.ContextEnvironment
Dependencies *build.ArtifactDependencies
WorkDir string
RepoName string
Dependencies *build.ArtifactDependencies
ContextEnvironment vcs.ContextEnvironment
Cmd *cobra.Command
}
9 changes: 4 additions & 5 deletions pkg/intoto/provenance.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package intoto

import (
"time"

slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
)

Expand All @@ -13,7 +11,7 @@ func GenerateSlsaPredicate(opts *ProvenanceOptions) *slsa.ProvenancePredicate {
},
BuildType: opts.BuildType,
BuildConfig: opts.BuildConfig,
Metadata: withMetadata(opts, time.Now().UTC()),
Metadata: withMetadata(opts),
Materials: withMaterials(opts),
}

Expand All @@ -25,11 +23,12 @@ func GenerateSlsaPredicate(opts *ProvenanceOptions) *slsa.ProvenancePredicate {
return predicate
}

func withMetadata(opts *ProvenanceOptions, buildFinished time.Time) *slsa.ProvenanceMetadata {
func withMetadata(opts *ProvenanceOptions) *slsa.ProvenanceMetadata {
timeFinished := opts.GetBuildFinishedOn()
return &slsa.ProvenanceMetadata{
BuildInvocationID: opts.BuildInvocationId,
BuildStartedOn: &opts.BuildStartedOn,
BuildFinishedOn: &buildFinished,
BuildFinishedOn: &timeFinished,
Completeness: withCompleteness(opts),
Reproducible: opts.Reproducible(),
}
Expand Down
51 changes: 45 additions & 6 deletions pkg/intoto/provenance_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/nais/salsa/pkg/build"
"github.com/nais/salsa/pkg/config"
"github.com/nais/salsa/pkg/vcs"
log "github.com/sirupsen/logrus"
"time"

slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
Expand All @@ -20,6 +21,7 @@ type ProvenanceOptions struct {
BuilderId string
BuilderRepoDigest *slsa.ProvenanceMaterial
BuildInvocationId string
BuildFinishedOn *time.Time
BuildStartedOn time.Time
BuildType string
Dependencies *build.ArtifactDependencies
Expand All @@ -29,14 +31,15 @@ type ProvenanceOptions struct {

func CreateProvenanceOptions(scanCfg *config.ScanConfiguration) *ProvenanceOptions {
opts := &ProvenanceOptions{
BuildStartedOn: time.Now().UTC(),
BuilderId: DefaultBuildId,
BuildType: AdHocBuildType,
Dependencies: scanCfg.Dependencies,
Name: scanCfg.RepoName,
BuilderId: DefaultBuildId,
BuildType: AdHocBuildType,
Dependencies: scanCfg.Dependencies,
Name: scanCfg.RepoName,
}

context := scanCfg.ContextEnvironment
opts.BuildStartedOn = buildStartedOn(context, scanCfg.BuildStartedOn)

if context != nil {
opts.BuildType = context.BuildType()
opts.BuildInvocationId = context.BuildInvocationId()
Expand Down Expand Up @@ -106,7 +109,7 @@ func (in *ProvenanceOptions) Parameters() bool {
return false
}

return in.Invocation.Parameters.(*vcs.Event).Inputs != nil
return in.Invocation.Parameters.(*vcs.Event).EventMetadata != nil
}

func (in *ProvenanceOptions) Environment() bool {
Expand All @@ -124,3 +127,39 @@ func (in *ProvenanceOptions) Materials() bool {
func (in *ProvenanceOptions) Reproducible() bool {
return in.Environment() && in.Materials() && in.Parameters()
}

func (in *ProvenanceOptions) GetBuildFinishedOn() time.Time {
if in.BuildFinishedOn == nil {
return time.Now().UTC().Round(time.Second)
}
return *in.BuildFinishedOn
}

func buildStartedOn(context vcs.ContextEnvironment, inputBuildTime string) time.Time {
if inputBuildTime != "" {
return buildStarted(inputBuildTime)
}

if context == nil {
return time.Now().UTC().Round(time.Second)
}

event := context.GetEvent()

if event == nil {
return time.Now().UTC().Round(time.Second)
}

return buildStarted(event.GetHeadCommitTimestamp())

}

func buildStarted(buildTime string) time.Time {
started, err := time.Parse(time.RFC3339, buildTime)
if err != nil {
log.Warnf("Failed to parse build time: %v, using default start time", err)
return time.Now().UTC().Round(time.Second)
}

return started
}
18 changes: 12 additions & 6 deletions pkg/intoto/provenance_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"github.com/nais/salsa/pkg/build"
"github.com/nais/salsa/pkg/config"
"github.com/nais/salsa/pkg/vcs"
"github.com/nais/salsa/pkg/vcs/github"
"github.com/spf13/cobra"
"os"
"testing"
Expand Down Expand Up @@ -63,6 +62,7 @@ func TestCreateProvenanceOptions(t *testing.T) {
assert.NoError(t, err)
env := Environment()
scanCfg := &config.ScanConfiguration{
BuildStartedOn: "",
WorkDir: "",
RepoName: "artifact",
Dependencies: artDeps,
Expand All @@ -73,7 +73,7 @@ func TestCreateProvenanceOptions(t *testing.T) {
assert.Equal(t, "artifact", provenanceArtifact.Name)
assert.Equal(t, test.buildType, provenanceArtifact.BuildType)
assert.Equal(t, deps, provenanceArtifact.Dependencies.RuntimeDeps)
assert.Equal(t, test.buildTimerIsSet, time.Now().UTC().After(provenanceArtifact.BuildStartedOn))
assert.Equal(t, "2022-02-14T09:38:16+01:00", provenanceArtifact.BuildStartedOn.Format(time.RFC3339))
assert.Equal(t, test.buildInvocationId, provenanceArtifact.BuildInvocationId)
assert.Equal(t, test.buildConfig, provenanceArtifact.BuildConfig)
assert.NotEmpty(t, provenanceArtifact.Invocation)
Expand All @@ -86,6 +86,7 @@ func TestCreateProvenanceOptions(t *testing.T) {
} else {

scanCfg := &config.ScanConfiguration{
BuildStartedOn: time.Now().UTC().Round(time.Second).Add(-10 * time.Minute).Format(time.RFC3339),
WorkDir: "",
RepoName: "artifact",
Dependencies: artDeps,
Expand Down Expand Up @@ -140,7 +141,7 @@ func ExpectedArtDeps(deps map[string]build.Dependency) *build.ArtifactDependenci

func Environment() *vcs.GithubCIEnvironment {
return &vcs.GithubCIEnvironment{
BuildContext: &github.Context{
BuildContext: &vcs.GithubContext{
Repository: "nais/salsa",
RunId: "1234",
SHA: "4321",
Expand All @@ -149,14 +150,19 @@ func Environment() *vcs.GithubCIEnvironment {
EventName: "workflow_dispatch",
},
Event: &vcs.Event{
Inputs: []byte("some user inputs"),
EventMetadata: &vcs.EventMetadata{
HeadCommit: &vcs.HeadCommit{
Id: "yolo",
Timestamp: "2022-02-14T09:38:16+01:00",
},
},
},
RunnerContext: &github.RunnerContext{
RunnerContext: &vcs.RunnerContext{
OS: "Linux",
Temp: "/home/runner/work/_temp",
ToolCache: "/opt/hostedtoolcache",
},
Actions: github.BuildId("v1"),
Actions: vcs.BuildId("v1"),
}
}

Expand Down
Loading