Skip to content
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/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ jobs:
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
continue-on-error: false
with:
version: v2.9.0
version: v2.13.2
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ linters:
# Highly annoying. We'd need to whitelist all packages we import, which is a lot of work and adds very little value.
- depguard
# Annoying and unhelpful. Assumes uninitialized (zero-valued) fields are always a bug, which is plain wrong.
- exhaustruct_v5
# Deprecated alias of exhaustruct_v5; keep it off too so it doesn't emit a deprecation warning.
- exhaustruct
# Marks [TODO, FIXME, BUG] comments as errors. We use these, so this is not helpful - unless we decide this is a good policy.
- godox
Expand Down Expand Up @@ -40,6 +42,8 @@ linters:
- nilnil
# Deprecated alias of wsl_v5; keep it off so only wsl_v5 runs (avoids a deprecation warning).
- wsl
# Deprecated alias of gomodguard_v2; keep it off so only gomodguard_v2 runs (avoids a deprecation warning).
- gomodguard
settings:
ireturn:
allow:
Expand Down
1 change: 1 addition & 0 deletions clerk/clerk.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func FetchJwt(ctx context.Context) (string, error) { //nolint:funlen,cyclop
Domain: GetClerkDomain(),
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
})
}

Expand Down
8 changes: 4 additions & 4 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ func formatGlobalPromptMessage(integrations []integrationRemovedObjectsInfo) str
for _, info := range integrations {
objectList := strings.Join(info.removedObjects, ", ")
installationWord := pluralizer.Pluralize("installation", info.installationCount, false)
lines.WriteString(fmt.Sprintf(" • %s: %s (%d %s)\n",
info.integrationName, objectList, info.installationCount, installationWord))
fmt.Fprintf(&lines, " • %s: %s (%d %s)\n",
info.integrationName, objectList, info.installationCount, installationWord)
}

message += lines.String()
Expand All @@ -378,11 +378,11 @@ func formatGlobalPromptMessage(integrations []integrationRemovedObjectsInfo) str
func formatAffectedInstallations(groups []groupInfo, totalCount int) string {
var result strings.Builder
for _, g := range groups {
result.WriteString(fmt.Sprintf("\n - %s (%s)", g.name, g.ref))
fmt.Fprintf(&result, "\n - %s (%s)", g.name, g.ref)
}

if totalCount > len(groups) {
result.WriteString(fmt.Sprintf("\n - and %d more", totalCount-len(groups)))
fmt.Fprintf(&result, "\n - and %d more", totalCount-len(groups))
}

return result.String()
Expand Down
11 changes: 9 additions & 2 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ func (h *handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {

writer.WriteHeader(http.StatusOK)

// rsp is the login-success page rendered by clerk.getHTML, whose only
// interpolation is mustache's {{email}} -- the escaping form, so the claim
// value cannot inject markup. gosec's taint analysis cannot see through the
// template engine.
// nosemgrep: go.lang.security.audit.xss.no-direct-write-to-responsewriter.no-direct-write-to-responsewriter
_, _ = writer.Write([]byte(rsp))
_, _ = writer.Write([]byte(rsp)) //nolint:gosec // G705: template-escaped, see above

go func() {
// Tell the user we're done and then forcefully exit the program.
Expand Down Expand Up @@ -87,7 +91,10 @@ func processLogin(ctx context.Context, payload []byte, write bool) (string, stri

path := clerk.GetJwtPath()
if write {
err := os.WriteFile(path, pretty.Pretty(payload), JwtFilePermissions)
// path is the XDG config path for this stage (clerk.GetJwtPath). The only
// caller-influenced part is AMP_STAGE_OVERRIDE, an env var the user sets for
// themselves on their own machine, so there is no cross-trust-boundary taint.
err := os.WriteFile(path, pretty.Pretty(payload), JwtFilePermissions) //nolint:gosec // G703: user's own config path
if err != nil {
return "", "", err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func openInEditor(ctx context.Context, data []byte) ([]byte, error) {
// vi/notepad fallback) and runs locally as the invoking user, so there is
// no untrusted input and no injection surface here.
// nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command
cmd := exec.CommandContext(ctx, editor, tmpFile.Name())
cmd := exec.CommandContext(ctx, editor, tmpFile.Name()) //nolint:gosec // G702: user's own $EDITOR, see above
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand Down
27 changes: 16 additions & 11 deletions files/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import (
"github.com/amp-labs/cli/openapi"
)

const (
objAccounts = "accounts"
objContacts = "contacts"
)

func TestGetRemovedReadObjects(t *testing.T) {
t.Parallel()

Expand All @@ -21,15 +26,15 @@ func TestGetRemovedReadObjects(t *testing.T) {
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "Accounts"},
{ObjectName: "contacts"},
{ObjectName: objContacts},
},
},
},
newInteg: &openapi.Integration{
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "accounts"},
{ObjectName: "contacts"},
{ObjectName: objAccounts},
{ObjectName: objContacts},
},
},
},
Expand All @@ -41,41 +46,41 @@ func TestGetRemovedReadObjects(t *testing.T) {
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "AccounTs"},
{ObjectName: "contacts"},
{ObjectName: objContacts},
},
},
},
newInteg: &openapi.Integration{
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "accounts"},
{ObjectName: objAccounts},
},
},
},
want: []string{"contacts"},
want: []string{objContacts},
},
{
name: "all objects removed",
oldRevision: &openapi.Integration{
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "accounts"},
{ObjectName: "contacts"},
{ObjectName: objAccounts},
{ObjectName: objContacts},
},
},
},
newInteg: &openapi.Integration{
Read: nil,
},
want: []string{"accounts", "contacts"},
want: []string{objAccounts, objContacts},
},
{
name: "no old read config",
oldRevision: &openapi.Integration{},
newInteg: &openapi.Integration{
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "accounts"},
{ObjectName: objAccounts},
},
},
},
Expand All @@ -87,7 +92,7 @@ func TestGetRemovedReadObjects(t *testing.T) {
newInteg: &openapi.Integration{
Read: &openapi.IntegrationRead{
Objects: &[]openapi.IntegrationObject{
{ObjectName: "accounts"},
{ObjectName: objAccounts},
},
},
},
Expand Down
13 changes: 5 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/amp-labs/cli

go 1.26.4
go 1.27.1

require (
github.com/adrg/xdg v0.5.3
Expand All @@ -18,13 +18,6 @@ require (
sigs.k8s.io/yaml v1.6.0
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.40.0 // indirect
)

require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
Expand All @@ -34,15 +27,19 @@ require (
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.54.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.40.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
17 changes: 11 additions & 6 deletions request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import (
"github.com/amp-labs/cli/utils"
)

const clientName = "amp-cli"
const (
clientName = "amp-cli"

headerContentType = "Content-Type"
mimeApplicationJSON = "application/json"
)

type Client struct {
Client *http.Client
Expand Down Expand Up @@ -209,7 +214,7 @@ func (c *Client) makeRequestAndParseJSONResult(req *http.Request, result any) (*
}

if res.StatusCode < 200 || res.StatusCode > 299 { //nolint:nestif
ct := res.Header.Get("Content-Type")
ct := res.Header.Get(headerContentType)
if len(ct) > 0 {
mt, _, err := mime.ParseMediaType(ct)
if err == nil {
Expand Down Expand Up @@ -291,7 +296,7 @@ func makeJSONPatchRequest(ctx context.Context, url string, headers []Header, bod

addDebugHeader(req)

headers = append(headers, Header{Key: "Content-Type", Value: "application/json"})
headers = append(headers, Header{Key: headerContentType, Value: mimeApplicationJSON})
req.ContentLength = int64(len(jBody))

return addAcceptJSONHeaders(req, headers)
Expand All @@ -310,7 +315,7 @@ func makeJSONPostRequest(ctx context.Context, url string, headers []Header, body

addDebugHeader(req)

headers = append(headers, Header{Key: "Content-Type", Value: "application/json"})
headers = append(headers, Header{Key: headerContentType, Value: mimeApplicationJSON})
req.ContentLength = int64(len(jBody))

return addAcceptJSONHeaders(req, headers)
Expand All @@ -329,7 +334,7 @@ func makeJSONPutRequest(ctx context.Context, url string, headers []Header, body

addDebugHeader(req)

headers = append(headers, Header{Key: "Content-Type", Value: "application/json"})
headers = append(headers, Header{Key: headerContentType, Value: mimeApplicationJSON})
req.ContentLength = int64(len(jBody))

return addAcceptJSONHeaders(req, headers)
Expand Down Expand Up @@ -359,7 +364,7 @@ func addHeaders(req *http.Request, headers []Header) *http.Request {

func addAcceptJSONHeaders(req *http.Request, headers []Header) (*http.Request, error) {
// Request JSON
req.Header.Add("Accept", "application/json")
req.Header.Add("Accept", mimeApplicationJSON)

// Apply any custom headers
for _, hdr := range headers {
Expand Down
3 changes: 1 addition & 2 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ func ReadStruct(r io.Reader, out any) (Format, error) {

// A JSON syntax error means the data may still be YAML, so fall through. Any other
// error means the data is JSON-shaped but invalid (e.g. a type mismatch); report it.
var se *json.SyntaxError
if !errors.As(err, &se) {
if _, ok := errors.AsType[*json.SyntaxError](err); !ok {
return Unknown, err
}

Expand Down
Loading