Skip to content

Commit d982514

Browse files
committed
docker-container: write github actions payload to container for provenance
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
1 parent f478741 commit d982514

3 files changed

Lines changed: 219 additions & 17 deletions

File tree

‎driver/docker-container/driver.go‎

Lines changed: 180 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package docker
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"io"
78
"net"
89
"os"
910
"path"
1011
"path/filepath"
12+
"strconv"
1113
"strings"
1214
"sync/atomic"
1315
"time"
@@ -43,20 +45,21 @@ type Driver struct {
4345

4446
// if you add fields, remember to update docs:
4547
// https://github.com/docker/docs/blob/main/content/build/drivers/docker-container.md
46-
netMode string
47-
image string
48-
memory opts.MemBytes
49-
memorySwap opts.MemSwapBytes
50-
cpuQuota int64
51-
cpuPeriod int64
52-
cpuShares int64
53-
cpusetCpus string
54-
cpusetMems string
55-
cgroupParent string
56-
restartPolicy container.RestartPolicy
57-
env []string
58-
defaultLoad bool
59-
gpus []container.DeviceRequest
48+
netMode string
49+
image string
50+
memory opts.MemBytes
51+
memorySwap opts.MemSwapBytes
52+
cpuQuota int64
53+
cpuPeriod int64
54+
cpuShares int64
55+
cpusetCpus string
56+
cpusetMems string
57+
cgroupParent string
58+
restartPolicy container.RestartPolicy
59+
env []string
60+
defaultLoad bool
61+
gpus []container.DeviceRequest
62+
setProvenanceGHA bool
6063
}
6164

6265
func (d *Driver) IsMobyDriver() bool {
@@ -137,6 +140,17 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
137140
},
138141
}
139142

143+
if d.setProvenanceGHA {
144+
if ghactx, err := githubActionsContext(); err != nil {
145+
return err
146+
} else if ghactx != nil {
147+
if d.Files == nil {
148+
d.Files = make(map[string][]byte)
149+
}
150+
d.Files["provenance.d/github_actions_context.json"] = ghactx
151+
}
152+
}
153+
140154
// Mount WSL libaries if running in WSL environment and Docker context
141155
// is a local socket as requesting GPU on container builder creation
142156
// is not enough when generating the CDI specification for GPU devices.
@@ -564,3 +578,155 @@ func isSocket(addr string) bool {
564578
return false
565579
}
566580
}
581+
582+
func githubActionsContext() ([]byte, error) {
583+
m := make(map[string]any)
584+
585+
// Detect if running in GitHub Actions
586+
// "GITHUB_ACTIONS": "true"
587+
if gha, ok := os.LookupEnv("GITHUB_ACTIONS"); !ok {
588+
return nil, nil
589+
} else if v, _ := strconv.ParseBool(gha); !v {
590+
return nil, nil
591+
}
592+
593+
// Skip if required event information is not available
594+
githubEventName := os.Getenv("GITHUB_EVENT_NAME")
595+
githubEventPath := os.Getenv("GITHUB_EVENT_PATH")
596+
if githubEventName == "" || githubEventPath == "" {
597+
return nil, nil
598+
}
599+
600+
// GitHub event
601+
// "GITHUB_EVENT_NAME": "push"
602+
// "GITHUB_EVENT_PATH": "/home/runner/work/_temp/_github_workflow/event.json"
603+
m["github_event_name"] = githubEventName
604+
dt, err := os.ReadFile(githubEventPath)
605+
if err != nil {
606+
return nil, errors.Wrapf(err, "failed to read GITHUB_EVENT_PATH %q", githubEventPath)
607+
}
608+
var evt map[string]any
609+
if err := json.Unmarshal(dt, &evt); err != nil {
610+
return nil, errors.Wrapf(err, "failed to unmarshal GitHub event payload from %q", githubEventPath)
611+
}
612+
m["github_event_payload"] = evt
613+
614+
// GitHub actor
615+
// "GITHUB_ACTOR": "crazy-max"
616+
// "GITHUB_ACTOR_ID": "1951866"
617+
// "GITHUB_TRIGGERING_ACTOR": "crazy-max"
618+
githubActor := os.Getenv("GITHUB_ACTOR")
619+
githubActorID := os.Getenv("GITHUB_ACTOR_ID")
620+
githubTriggeringActor := os.Getenv("GITHUB_TRIGGERING_ACTOR")
621+
if githubActor != "" && githubActorID != "" && githubTriggeringActor != "" {
622+
m["github_actor"] = githubActor
623+
m["github_actor_id"] = githubActorID
624+
m["github_triggering_actor"] = githubTriggeringActor
625+
}
626+
627+
// GitHub ref
628+
// "GITHUB_REF": "refs/heads/master"
629+
// "GITHUB_REF_NAME": "master"
630+
// "GITHUB_REF_PROTECTED": "true"
631+
// "GITHUB_REF_TYPE": "branch"
632+
githubRef := os.Getenv("GITHUB_REF")
633+
githubRefName := os.Getenv("GITHUB_REF_NAME")
634+
githubRefProtected := os.Getenv("GITHUB_REF_PROTECTED")
635+
githubRefType := os.Getenv("GITHUB_REF_TYPE")
636+
if githubRef != "" && githubRefName != "" && githubRefProtected != "" && githubRefType != "" {
637+
m["github_ref"] = githubRef
638+
m["github_ref_name"] = githubRefName
639+
m["github_ref_protected"] = githubRefProtected
640+
m["github_ref_type"] = githubRefType
641+
}
642+
643+
// GitHub repository
644+
// "GITHUB_REPOSITORY": "crazy-max/ghaction-dump-context"
645+
// "GITHUB_REPOSITORY_ID": "286865579"
646+
// "GITHUB_REPOSITORY_OWNER": "crazy-max"
647+
// "GITHUB_REPOSITORY_OWNER_ID": "1951866"
648+
githubRepository := os.Getenv("GITHUB_REPOSITORY")
649+
githubRepositoryID := os.Getenv("GITHUB_REPOSITORY_ID")
650+
githubRepositoryOwner := os.Getenv("GITHUB_REPOSITORY_OWNER")
651+
githubRepositoryOwnerID := os.Getenv("GITHUB_REPOSITORY_OWNER_ID")
652+
if githubRepository != "" && githubRepositoryID != "" && githubRepositoryOwner != "" && githubRepositoryOwnerID != "" {
653+
m["github_repository"] = githubRepository
654+
m["github_repository_id"] = githubRepositoryID
655+
m["github_repository_owner"] = githubRepositoryOwner
656+
m["github_repository_owner_id"] = githubRepositoryOwnerID
657+
}
658+
659+
// GitHub workflow
660+
// "GITHUB_JOB": "dump"
661+
// "GITHUB_RUN_ATTEMPT": "1"
662+
// "GITHUB_RUN_ID": "18715517508"
663+
// "GITHUB_RUN_NUMBER": "617"
664+
// "GITHUB_SERVER_URL": "https://github.com"
665+
// "GITHUB_WORKFLOW": "ci"
666+
// "GITHUB_WORKFLOW_REF": "crazy-max/ghaction-dump-context/.github/workflows/ci.yml@refs/heads/master"
667+
// "GITHUB_WORKFLOW_SHA": "391d493f5fb04040f2a2770b33f86f3f62518392"
668+
githubJob := os.Getenv("GITHUB_JOB")
669+
githubRunAttempt := os.Getenv("GITHUB_RUN_ATTEMPT")
670+
githubRunID := os.Getenv("GITHUB_RUN_ID")
671+
githubRunNumber := os.Getenv("GITHUB_RUN_NUMBER")
672+
githubServerURL := os.Getenv("GITHUB_SERVER_URL")
673+
githubWorkflow := os.Getenv("GITHUB_WORKFLOW")
674+
githubWorkflowRef := os.Getenv("GITHUB_WORKFLOW_REF")
675+
githubWorkflowSHA := os.Getenv("GITHUB_WORKFLOW_SHA")
676+
if githubJob != "" && githubRunAttempt != "" && githubRunID != "" && githubRunNumber != "" && githubServerURL != "" && githubWorkflow != "" && githubWorkflowRef != "" && githubWorkflowSHA != "" {
677+
m["github_job"] = githubJob
678+
m["github_run_attempt"] = githubRunAttempt
679+
m["github_run_id"] = githubRunID
680+
m["github_run_number"] = githubRunNumber
681+
m["github_server_url"] = githubServerURL
682+
m["github_workflow"] = githubWorkflow
683+
m["github_workflow_ref"] = githubWorkflowRef
684+
m["github_workflow_sha"] = githubWorkflowSHA
685+
}
686+
687+
// GitHub action
688+
// "GITHUB_ACTION": "__self"
689+
// "GITHUB_ACTION_PATH": "/home/runner/work/ghaction-dump-context/ghaction-dump-context/./"
690+
// "GITHUB_ACTION_REF": "v7"
691+
// "GITHUB_ACTION_REPOSITORY": "actions/github-script"
692+
githubAction := os.Getenv("GITHUB_ACTION")
693+
githubActionPath := os.Getenv("GITHUB_ACTION_PATH")
694+
githubActionRef := os.Getenv("GITHUB_ACTION_REF")
695+
githubActionRepository := os.Getenv("GITHUB_ACTION_REPOSITORY")
696+
if githubAction != "" && githubActionPath != "" && githubActionRef != "" && githubActionRepository != "" {
697+
m["github_action"] = githubAction
698+
m["github_action_path"] = githubActionPath
699+
m["github_action_ref"] = githubActionRef
700+
m["github_action_repository"] = githubActionRepository
701+
}
702+
703+
// GitHub runner information
704+
// "ImageOS": "ubuntu24"
705+
// "ImageVersion": "20250929.60.1"
706+
// "RUNNER_ARCH": "X64"
707+
// "RUNNER_ENVIRONMENT": "github-hosted"
708+
// "RUNNER_NAME": "GitHub Actions 1000091440"
709+
// "RUNNER_OS": "Linux"
710+
// "RUNNER_TEMP": "/home/runner/work/_temp"
711+
// "RUNNER_TOOL_CACHE": "/opt/hostedtoolcache"
712+
// "RUNNER_TRACKING_ID": "github_7bd1d852-eaeb-423f-8fa4-4ddb797c652f"
713+
// "RUNNER_WORKSPACE": "/home/runner/work/ghaction-dump-context"
714+
githubRunnerImageOS := os.Getenv("ImageOS")
715+
githubRunnerImageVersion := os.Getenv("ImageVersion")
716+
githubRunnerOS := os.Getenv("RUNNER_OS")
717+
githubRunnerArch := os.Getenv("RUNNER_ARCH")
718+
githubRunnerEnvironment := os.Getenv("RUNNER_ENVIRONMENT")
719+
githubRunnerTrackingID := os.Getenv("RUNNER_TRACKING_ID")
720+
githubRunnerName := os.Getenv("RUNNER_NAME")
721+
if githubRunnerImageOS != "" && githubRunnerImageVersion != "" && githubRunnerOS != "" && githubRunnerArch != "" && githubRunnerEnvironment != "" && githubRunnerTrackingID != "" && githubRunnerName != "" {
722+
m["github_runner_image_os"] = githubRunnerImageOS
723+
m["github_runner_image_version"] = githubRunnerImageVersion
724+
m["github_runner_os"] = githubRunnerOS
725+
m["github_runner_arch"] = githubRunnerArch
726+
m["github_runner_environment"] = githubRunnerEnvironment
727+
m["github_runner_tracking_id"] = githubRunnerTrackingID
728+
m["github_runner_name"] = githubRunnerName
729+
}
730+
731+
return json.Marshal(m)
732+
}

‎driver/docker-container/factory.go‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
4747
return nil, err
4848
}
4949
d := &Driver{
50-
factory: f,
51-
InitConfig: cfg,
52-
restartPolicy: rp,
50+
factory: f,
51+
InitConfig: cfg,
52+
restartPolicy: rp,
53+
setProvenanceGHA: true,
5354
}
5455
var gpus dockeropts.GpuOpts
5556
if err := gpus.Set("all"); err == nil {
@@ -111,6 +112,11 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
111112
return nil, errors.Errorf("invalid env option %q, expecting env.FOO=bar", k)
112113
}
113114
d.env = append(d.env, fmt.Sprintf("%s=%s", envName, v))
115+
case k == "provenance-add-gha":
116+
d.setProvenanceGHA, err = strconv.ParseBool(v)
117+
if err != nil {
118+
return nil, err
119+
}
114120
default:
115121
return nil, errors.Errorf("invalid driver option %s for docker-container driver", k)
116122
}

‎tests/create.go‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tests
33
import (
44
"fmt"
55
"os"
6+
"path/filepath"
67
"strings"
78
"testing"
89

@@ -23,6 +24,7 @@ var createTests = []func(t *testing.T, sb integration.Sandbox){
2324
testCreateMemoryLimit,
2425
testCreateRestartAlways,
2526
testCreateRemoteContainer,
27+
testCreateWithProvenanceGHA,
2628
}
2729

2830
func testCreateMemoryLimit(t *testing.T, sb integration.Sandbox) {
@@ -108,3 +110,31 @@ func testCreateRemoteContainer(t *testing.T, sb integration.Sandbox) {
108110
}
109111
require.Fail(t, "remote builder is not running")
110112
}
113+
114+
func testCreateWithProvenanceGHA(t *testing.T, sb integration.Sandbox) {
115+
if !isDockerContainerWorker(sb) {
116+
t.Skip("only testing with docker-container worker")
117+
}
118+
119+
var builderName string
120+
t.Cleanup(func() {
121+
if builderName == "" {
122+
return
123+
}
124+
out, err := rmCmd(sb, withArgs(builderName))
125+
require.NoError(t, err, out)
126+
})
127+
128+
ghep := filepath.Join(t.TempDir(), "event.json")
129+
require.NoError(t, os.WriteFile(ghep, []byte(`{"test":{"foo":"bar"}}`), 0644))
130+
131+
out, err := createCmd(sb,
132+
withArgs("--driver", "docker-container"),
133+
withEnv("GITHUB_ACTIONS=true", "GITHUB_EVENT_NAME=push", "GITHUB_EVENT_PATH="+ghep),
134+
)
135+
require.NoError(t, err, out)
136+
builderName = strings.TrimSpace(out)
137+
138+
out, err = inspectCmd(sb, withArgs(builderName, "--bootstrap"))
139+
require.NoError(t, err, out)
140+
}

0 commit comments

Comments
 (0)