Fail closed on inconclusive parity under the Dependabot proxy · github/gh-actions-lock@159c824 · GitHub
Skip to content

Commit 159c824

Browse files
committed
Fail closed on inconclusive parity under the Dependabot proxy
Behind the proxy every dotcom call shares one rate-limit bucket, so a 403, 429, or 5xx turned each re-checked pin into a warning and the run passed. Abort with exit 2 instead so Dependabot retries.
1 parent df4d2f4 commit 159c824

4 files changed

Lines changed: 97 additions & 8 deletions

File tree

‎cmd/gh-actions-lock/parity_test.go‎

Lines changed: 71 additions & 0 deletions

‎internal/ghapi/client.go‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ func New(hostname string, opts ...ClientOption) (*Client, error) {
109109
return &Client{Hostname: hostname, local: local, public: public, pinned: map[Repo]string{}}, nil
110110
}
111111

112+
// DependabotProxy reports whether the CLI runs inside Dependabot, behind its
113+
// REST-only proxy. Dependabot retries on exit 2 and reads back only
114+
// actions.lock.
115+
func DependabotProxy() bool {
116+
return os.Getenv("GH_ACTIONS_LOCK_DEPENDABOT_PROXY") == "1"
117+
}
118+
112119
func newClient(hostname string, opts ...ClientOption) (*Client, error) {
113120
var cfg clientConfig
114121
for _, o := range opts {
@@ -117,7 +124,7 @@ func newClient(hostname string, opts ...ClientOption) (*Client, error) {
117124

118125
c := &Client{
119126
Hostname: hostname,
120-
restOnly: os.Getenv("GH_ACTIONS_LOCK_DEPENDABOT_PROXY") == "1",
127+
restOnly: DependabotProxy(),
121128
}
122129

123130
apiOpts := api.ClientOptions{Host: hostname}

‎internal/pipeline/parity.go‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ import (
2929
// transfer redirect to the same repo ID is a warning, also inside a
3030
// remote composite; a different ID or a name that doesn't resolve blocks. Fresh pins fail closed: an
3131
// inconclusive check keeps them out of the write.
32-
func checkParity(ctx context.Context, r *resolve.Resolver, parsed []checks.ParsedWorkflow, store *lockfile.State, report *checks.Report, recordedKeys map[string]bool, resolved []dep.Dependency, parents map[string][]string, keep func(checks.Category) bool) {
32+
//
33+
// Under the Dependabot proxy any inconclusive check is an error: the run
34+
// aborts so Dependabot retries rather than shipping an unverified lock.
35+
func checkParity(ctx context.Context, r *resolve.Resolver, parsed []checks.ParsedWorkflow, store *lockfile.State, report *checks.Report, recordedKeys map[string]bool, resolved []dep.Dependency, parents map[string][]string, keep func(checks.Category) bool) error {
3336
gh := r.GHClient()
3437
if gh == nil || store == nil {
35-
return
38+
return nil
3639
}
3740
reportIdx := make(map[string]int, len(report.Workflows))
3841
for i, wr := range report.Workflows {
@@ -97,12 +100,19 @@ func checkParity(ctx context.Context, r *resolve.Resolver, parsed []checks.Parse
97100
}
98101
}
99102
if len(pins) == 0 {
100-
return
103+
return nil
101104
}
102105

103106
states := gh.CheckPins(ctx, pins)
104107
if ctx.Err() != nil {
105-
return
108+
return ctx.Err()
109+
}
110+
if ghapi.DependabotProxy() {
111+
for i, st := range states {
112+
if st.Err != nil {
113+
return fmt.Errorf("could not verify locked %s/%s@%s: %w", pins[i].Owner, pins[i].Repo, parserlock.ShortSHA(pins[i].SHA), st.Err)
114+
}
115+
}
106116
}
107117
for i, st := range states {
108118
for _, o := range owners[i] {
@@ -125,6 +135,7 @@ func checkParity(ctx context.Context, r *resolve.Resolver, parsed []checks.Parse
125135
wr.Findings = append(wr.Findings, f)
126136
}
127137
}
138+
return nil
128139
}
129140

130141
type parityOwner struct {

‎internal/pipeline/run.go‎

Lines changed: 3 additions & 3 deletions

0 commit comments

Comments
 (0)