Skip to content

Commit 8782d00

Browse files
committed
chore: adding scope flags to cli [CSENG-68]
chore: revert unlreated changes in PR chore: revert unlreated changes in PR chore: revert unlreated changes in PR
1 parent 1734d5a commit 8782d00

28 files changed

+779
-128
lines changed

cliv2/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ require (
1515
github.com/snyk/cli-extension-iac v0.0.0-20250829110702-b41ac109dab0
1616
github.com/snyk/cli-extension-iac-rules v0.0.0-20260115114457-a8ac3358ec57
1717
github.com/snyk/cli-extension-mcp-scan v0.0.0-20260120142932-0eea0566625a
18-
github.com/snyk/cli-extension-os-flows v0.0.0-20260115160519-84f621016a34
18+
github.com/snyk/cli-extension-os-flows v0.0.0-20260126114133-44216d2c49f1
1919
github.com/snyk/cli-extension-sbom v0.0.0-20260109124810-cfdd074f8eeb
2020
github.com/snyk/container-cli v0.0.0-20250321132345-1e2e01681dd7
2121
github.com/snyk/error-catalog-golang-public v0.0.0-20260108110943-21ad0c940c14

cliv2/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,8 @@ github.com/snyk/cli-extension-iac-rules v0.0.0-20260115114457-a8ac3358ec57 h1:8A
532532
github.com/snyk/cli-extension-iac-rules v0.0.0-20260115114457-a8ac3358ec57/go.mod h1:AFto63ozNmCXtKb5oTTD3Qz1jEl/HCqCVwpZCfTpSIE=
533533
github.com/snyk/cli-extension-mcp-scan v0.0.0-20260120142932-0eea0566625a h1:ElZXU6njO7McDQ7u7nAsJ5PCcwvA2+dEsadRM4P41JQ=
534534
github.com/snyk/cli-extension-mcp-scan v0.0.0-20260120142932-0eea0566625a/go.mod h1:i/EDskKxg68MtWaIOWFyataAMtcXOb/DQPLxT5jtLRE=
535-
github.com/snyk/cli-extension-os-flows v0.0.0-20260115160519-84f621016a34 h1:VtbScRQpbpmOE6MqHhMHUhQszSUO83oeVUb7U8td0uE=
536-
github.com/snyk/cli-extension-os-flows v0.0.0-20260115160519-84f621016a34/go.mod h1:s3HX7yjdyP5PYe+ZTMyrJA5wv6hCnmfGdh7Nk5la6tY=
535+
github.com/snyk/cli-extension-os-flows v0.0.0-20260126114133-44216d2c49f1 h1:xlw3z5a6KrpoLXgoGjzjc3LyxDjZCxylHuiEoQ8U9No=
536+
github.com/snyk/cli-extension-os-flows v0.0.0-20260126114133-44216d2c49f1/go.mod h1:eYla0N+RzCa88JT6v4t/sAQthfJgyOHO1Oj9J72/Exw=
537537
github.com/snyk/cli-extension-sbom v0.0.0-20260109124810-cfdd074f8eeb h1:5cAi3VwdoE4d6kc6D6qSge11e/ALBMmuBatySFd8rfE=
538538
github.com/snyk/cli-extension-sbom v0.0.0-20260109124810-cfdd074f8eeb/go.mod h1:jIACVV10j4pW7LFrlYYtjn9mZm2JnXeFBM6/aTNJgvM=
539539
github.com/snyk/code-client-go v1.25.0 h1:1lcg6asMpMWwpaZLKVDdci3OrAv6rRoCsCcT8Ci/fUI=
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package interceptor
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"io"
7+
"net/http"
8+
"regexp"
9+
10+
"github.com/elazarl/goproxy"
11+
"github.com/snyk/go-application-framework/pkg/workflow"
12+
)
13+
14+
const FeatureFlagShowMavenBuildScope = "internal_snyk_show_maven_scope_enabled"
15+
const FeatureFlagShowNpmBuildScope = "internal_snyk_show_npm_scope_enabled"
16+
17+
type legacyFeatureFlagInterceptor struct {
18+
requestCondition goproxy.ReqCondition
19+
invocationCtx workflow.InvocationContext
20+
}
21+
22+
type featureFlagResponse struct {
23+
OK bool `json:"ok"`
24+
}
25+
26+
func (ni legacyFeatureFlagInterceptor) GetCondition() goproxy.ReqCondition {
27+
return ni.requestCondition
28+
}
29+
30+
// GetHandler for legacyFeatureFlagInterceptor will re-route all registry requests from the proxy to the configured feature flag values.
31+
// This ensures that we can control feature flag values for the legacy CLI from the CLIv2 configuration.
32+
// Currently, only the "show-maven-build-scope" and "show-npm-scope" feature flags are supported.
33+
func (ni legacyFeatureFlagInterceptor) GetHandler() goproxy.FuncReqHandler {
34+
return func(req *http.Request, proxyCtx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
35+
ni.invocationCtx.GetEnhancedLogger().Printf("legacyFeatureFlagInterceptor handling request for %s", req.URL.Path)
36+
var configKey string
37+
switch req.URL.Path {
38+
case "/v1/cli-config/feature-flags/show-maven-build-scope":
39+
configKey = FeatureFlagShowMavenBuildScope
40+
case "/v1/cli-config/feature-flags/show-npm-scope":
41+
configKey = FeatureFlagShowNpmBuildScope
42+
default:
43+
return req, nil
44+
}
45+
46+
enabled := ni.invocationCtx.
47+
GetConfiguration().
48+
GetBool(configKey)
49+
50+
payload := featureFlagResponse{OK: enabled}
51+
b, err := json.Marshal(payload)
52+
if err != nil {
53+
return req, nil
54+
}
55+
56+
resp := &http.Response{
57+
StatusCode: http.StatusOK,
58+
Status: "200 OK",
59+
Header: make(http.Header),
60+
Body: io.NopCloser(bytes.NewReader(b)),
61+
Request: req,
62+
}
63+
resp.Header.Set("Content-Type", "application/json")
64+
ni.invocationCtx.GetEnhancedLogger().Printf("legacyFeatureFlagInterceptor response for %s is %v", configKey, enabled)
65+
66+
return req, resp
67+
}
68+
}
69+
70+
func NewLegacyFeatureFlagInterceptor(invocationCtx workflow.InvocationContext) Interceptor {
71+
i := legacyFeatureFlagInterceptor{
72+
requestCondition: goproxy.UrlMatches(
73+
regexp.MustCompile(`/cli-config/feature-flags/(show-maven-build-scope|show-npm-scope)/?$`),
74+
),
75+
invocationCtx: invocationCtx,
76+
}
77+
return i
78+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package interceptor
2+
3+
import (
4+
"encoding/json"
5+
"io"
6+
"net/http"
7+
"net/http/httptest"
8+
"testing"
9+
10+
"github.com/golang/mock/gomock"
11+
"github.com/rs/zerolog"
12+
"github.com/snyk/go-application-framework/pkg/mocks"
13+
14+
"github.com/elazarl/goproxy"
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestLegacyFeatureFlagInterceptor_Routing(t *testing.T) {
19+
tests := []struct {
20+
name string
21+
path string
22+
shouldHandle bool
23+
configKey string // only used when shouldHandle == true
24+
}{
25+
{
26+
name: "maven path",
27+
path: "https://example.com/v1/cli-config/feature-flags/show-maven-build-scope?org=abc",
28+
shouldHandle: true,
29+
configKey: FeatureFlagShowMavenBuildScope,
30+
},
31+
{
32+
name: "npm path",
33+
path: "https://example.com/v1/cli-config/feature-flags/show-npm-scope?org=abc",
34+
shouldHandle: true,
35+
configKey: FeatureFlagShowNpmBuildScope,
36+
},
37+
{
38+
name: "other path",
39+
path: "https://example.com/api/v1/other-endpoint",
40+
shouldHandle: false,
41+
},
42+
}
43+
44+
for _, tt := range tests {
45+
t.Run(tt.name, func(t *testing.T) {
46+
ctrl := gomock.NewController(t)
47+
defer ctrl.Finish()
48+
49+
configMock := mocks.NewMockConfiguration(ctrl)
50+
51+
// Only expect config access when the interceptor should handle the path.
52+
if tt.shouldHandle {
53+
configMock.EXPECT().
54+
GetBool(tt.configKey).
55+
Return(true).
56+
AnyTimes()
57+
}
58+
59+
invocationCtxMock := mocks.NewMockInvocationContext(ctrl)
60+
invocationCtxMock.EXPECT().
61+
GetConfiguration().
62+
Return(configMock).
63+
AnyTimes()
64+
65+
interceptor := NewLegacyFeatureFlagInterceptor(invocationCtxMock)
66+
handler := interceptor.GetHandler()
67+
68+
req := httptest.NewRequest(http.MethodGet, tt.path, nil)
69+
proxyCtx := &goproxy.ProxyCtx{}
70+
71+
matched := interceptor.GetCondition().HandleReq(req, proxyCtx)
72+
assert.Equal(t, tt.shouldHandle, matched)
73+
74+
if !tt.shouldHandle {
75+
return
76+
}
77+
78+
logger := zerolog.Nop()
79+
invocationCtxMock.EXPECT().GetEnhancedLogger().Return(&logger).AnyTimes()
80+
81+
_, resp := handler(req, proxyCtx)
82+
assert.NotNil(t, resp)
83+
assert.Equal(t, http.StatusOK, resp.StatusCode)
84+
assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
85+
86+
bodyBytes, err := io.ReadAll(resp.Body)
87+
assert.NoError(t, err)
88+
89+
var parsed featureFlagResponse
90+
assert.NoError(t, json.Unmarshal(bodyBytes, &parsed))
91+
assert.True(t, parsed.OK)
92+
})
93+
}
94+
}

cliv2/pkg/basic_workflows/legacycli.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ func createInternalProxy(config configuration.Configuration, debugLogger *zerolo
190190
}
191191

192192
wrapperProxy.RegisterInterceptor(interceptor.NewV1AnalyticsInterceptor(invocation))
193+
wrapperProxy.RegisterInterceptor(interceptor.NewLegacyFeatureFlagInterceptor(invocation))
193194
// The networkinjector intercepts all requests from the legacy CLI and re-routes them to the existing networking
194195
// layer. It should therefore be kept as the last interceptor in the chain, as it circuit breaks goproxy's own
195196
// routing. Any interceptor added later will not be called.

0 commit comments

Comments
 (0)