diff --git a/.github/codeql/codeql-config.yaml b/.github/codeql/codeql-config.yaml new file mode 100644 index 00000000..aa78f45c --- /dev/null +++ b/.github/codeql/codeql-config.yaml @@ -0,0 +1,8 @@ +paths: + - pkg + - cmd + - internal + - test +paths-ignore: + - pkg/provisioner/provisioner.go + - cmd/cli/dryrun/dryrun.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..c5acdfe7 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,39 @@ +# Copyright 2025 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: CI Pipeline + +on: + push: + branches: + - "pull-request/[0-9]+" + - main + - release-* + +jobs: + code-scanning: + uses: ./.github/workflows/code_scanning.yaml + + golang: + uses: ./.github/workflows/golang.yaml + + image: + uses: ./.github/workflows/image.yaml + needs: [golang, code-scanning] + secrets: inherit + + e2e-test: + needs: golang + secrets: inherit + uses: ./.github/workflows/e2e.yaml diff --git a/.github/workflows/codeql.yml b/.github/workflows/code_scanning.yaml similarity index 94% rename from .github/workflows/codeql.yml rename to .github/workflows/code_scanning.yaml index 674cb838..d9600c09 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/code_scanning.yaml @@ -15,6 +15,7 @@ name: "CodeQL" on: + workflow_call: {} pull_request: types: - opened @@ -22,10 +23,6 @@ on: branches: - main - release-* - push: - branches: - - main - - release-* schedule: - cron: '31 11 * * 4' @@ -40,14 +37,18 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: + config-file: ./.github/codeql/codeql-config.yaml languages: go build-mode: manual + - shell: bash run: | make build-cli + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yaml similarity index 92% rename from .github/workflows/e2e.yml rename to .github/workflows/e2e.yaml index a186b981..a4506e4e 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yaml @@ -15,14 +15,14 @@ name: End-to-end Tests on: - workflow_run: - workflows: [Go] - types: - - completed - branches: - - "pull-request/[0-9]+" - - main - - release-* + workflow_call: + secrets: + AWS_ACCESS_KEY_ID: + required: true + AWS_SECRET_ACCESS_KEY: + required: true + AWS_SSH_KEY: + required: true jobs: e2e-test: diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 9e215402..00000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,39 +0,0 @@ -## Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## - -name: Go - -on: - push: - branches: - - main - - release-* - pull_request: - branches: - - main - - release-* - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: 'go.mod' - - - name: Build - run: go build -v ./... diff --git a/.github/workflows/golang.yaml b/.github/workflows/golang.yaml new file mode 100644 index 00000000..104a6b24 --- /dev/null +++ b/.github/workflows/golang.yaml @@ -0,0 +1,78 @@ +## Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +name: Go + +on: + workflow_call: {} + pull_request: + types: + - opened + - synchronize + branches: + - main + - release-* + +jobs: + variables: + runs-on: ubuntu-latest + outputs: + GOLANG_VERSION: ${{ steps.go_version.outputs.GOLANG_VERSION }} + steps: + - uses: actions/checkout@v4 + name: Checkout code + + - name: Get Golang version + id: go_version + run: | + GOLANG_VERSION=$(./hack/golang-version.sh) + echo "GOLANG_VERSION=${GOLANG_VERSION##GOLANG_VERSION := }" >> $GITHUB_OUTPUT + + check: + runs-on: ubuntu-latest + needs: variables + steps: + - uses: actions/checkout@v4 + name: Checkout code + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ needs.variables.outputs.GOLANG_VERSION }} + + - name: Lint + uses: golangci/golangci-lint-action@v6 + with: + version: latest + args: -v --timeout 5m + skip-cache: true + + - name: Check golang modules + run: | + make check-modules + + build: + name: Build + needs: variables + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ needs.variables.outputs.GOLANG_VERSION }} + + - run: make build-cli diff --git a/.github/workflows/image.yml b/.github/workflows/image.yaml similarity index 91% rename from .github/workflows/image.yml rename to .github/workflows/image.yaml index 0e1b3809..eb70d848 100644 --- a/.github/workflows/image.yml +++ b/.github/workflows/image.yaml @@ -15,16 +15,7 @@ name: Image on: - pull_request: - branches: - - 'main' - - 'release-*' - push: - tags: - - 'v*.*.*' - branches: - - 'main' - - 'release-*' + workflow_call: jobs: docker: diff --git a/.github/workflows/awscleanup.yaml b/.github/workflows/periodic.yaml similarity index 97% rename from .github/workflows/awscleanup.yaml rename to .github/workflows/periodic.yaml index 5bdec479..c3fd4e3c 100644 --- a/.github/workflows/awscleanup.yaml +++ b/.github/workflows/periodic.yaml @@ -1,4 +1,4 @@ -name: AWS Periodic Cleanup +name: Periodic actions on: schedule: diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..c5bc2124 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,22 @@ +run: + timeout: 10m + +linters: + enable: + - contextcheck + - errcheck + - gocritic + - gofmt + - goimports + - gosec + - gosimple + - govet + - ineffassign + - misspell + - staticcheck + - unconvert + disable: [] + +linters-settings: + goimports: + local-prefixes: github.com/NVIDIA/holodeck diff --git a/Makefile b/Makefile index 9ce39f1a..76be9f5a 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: build fmt verify release +.PHONY: build fmt verify release lint vendor mod-tidy mod-vendor mod-verify check-vendor GO_CMD ?= go GO_FMT ?= gofmt @@ -27,6 +27,44 @@ IMAGE_TAG := $(IMAGE_REPO):$(IMAGE_TAG_NAME) PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) +# Apply go fmt to the codebase +fmt: + go list -f '{{.Dir}}' $(MODULE)/... \ + | xargs gofmt -s -l -w + +goimports: + go list -f {{.Dir}} $(MODULE)/... \ + | xargs goimports -local $(MODULE) -w + +lint: + golangci-lint run ./... + +mod-tidy: + @for mod in $$(find . -name go.mod); do \ + echo "Tidying $$mod..."; ( \ + cd $$(dirname $$mod) && go mod tidy \ + ) || exit 1; \ + done + +mod-verify: + @for mod in $$(find . -name go.mod); do \ + echo "Verifying $$mod..."; ( \ + cd $$(dirname $$mod) && go mod verify | sed 's/^/ /g' \ + ) || exit 1; \ + done + +mod-vendor: mod-tidy + @for mod in $$(find . -name go.mod -not -path "./deployments/*"); do \ + echo "Vendoring $$mod..."; ( \ + cd $$(dirname $$mod) && go mod vendor \ + ) || exit 1; \ + done + +vendor: mod-vendor + +check-modules: | mod-tidy mod-verify mod-vendor + git diff --quiet HEAD -- $$(find . -name go.mod -o -name go.sum -o -name vendor) + build-action: @rm -rf bin GOOS=linux $(GO_CMD) build -o /go/bin/$(BINARY_NAME) cmd/action/main.go diff --git a/cmd/action/ci/ci.go b/cmd/action/ci/ci.go index b0c391cd..0929d300 100644 --- a/cmd/action/ci/ci.go +++ b/cmd/action/ci/ci.go @@ -17,8 +17,9 @@ package ci import ( + "crypto/rand" "fmt" - "math/rand" + "log" "os" "github.com/NVIDIA/holodeck/api/holodeck/v1alpha1" @@ -57,7 +58,7 @@ func Run(log *logger.FunLogger) error { log.Info("Environment condition is Terminated no need to run Holodeck") return nil } else if err != nil { - log.Warning(err.Error()) + log.Warning("%s", err.Error()) } if err := cleanup(log); err != nil { return err @@ -138,10 +139,15 @@ func setCfgName(cfg *v1alpha1.Environment) { func generateUID() string { const charset = "abcdefghijklmnopqrstuvwxyz0123456789" - b := make([]byte, 8) + + _, err := rand.Read(b) + if err != nil { + log.Fatalf("failed to generate secure random UID: %v", err) + } + for i := range b { - b[i] = charset[rand.Intn(len(charset))] + b[i] = charset[int(b[i])%len(charset)] } return string(b) diff --git a/cmd/cli/dryrun/dryrun.go b/cmd/cli/dryrun/dryrun.go index 0768edc4..c2b39dcb 100644 --- a/cmd/cli/dryrun/dryrun.go +++ b/cmd/cli/dryrun/dryrun.go @@ -26,9 +26,9 @@ import ( "github.com/NVIDIA/holodeck/pkg/jyaml" "github.com/NVIDIA/holodeck/pkg/provider/aws" "github.com/NVIDIA/holodeck/pkg/provisioner" - "golang.org/x/crypto/ssh" cli "github.com/urfave/cli/v2" + "golang.org/x/crypto/ssh" ) type options struct { @@ -75,14 +75,14 @@ func (m command) build() *cli.Command { return nil }, Action: func(c *cli.Context) error { - return m.run(c, &opts) + return m.run(&opts) }, } return &dryrun } -func (m command) run(c *cli.Context, opts *options) error { +func (m command) run(opts *options) error { m.log.Info("Dryrun environment %s \U0001f50d", opts.cfg.Name) // Check Provider @@ -143,7 +143,7 @@ func connectOrDie(keyPath, userName, hostUrl string) error { Auth: []ssh.AuthMethod{ ssh.PublicKeys(signer), }, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), + HostKeyCallback: ssh.InsecureIgnoreHostKey(), // nolint:gosec } connectionFailed := false diff --git a/hack/golang-version.sh b/hack/golang-version.sh new file mode 100755 index 00000000..81685cc7 --- /dev/null +++ b/hack/golang-version.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../hack && pwd )" + +DOCKERFILE_ROOT=${SCRIPTS_DIR}/../deployments/devel + +GOLANG_VERSION=$(grep -E "^FROM golang:.*$" ${DOCKERFILE_ROOT}/Dockerfile | grep -oE "[0-9\.]+") + +echo $GOLANG_VERSION diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 91fc4bfe..08b72d30 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -26,13 +26,6 @@ import ( "github.com/mattn/go-isatty" ) -var ( - // outFile is where Out* functions send output to. Set using SetOutFile() - outFile fdWriter - // errFile is where Err* functions send output to. Set using SetErrFile() - errFile fdWriter -) - // fdWriter is the subset of file.File that implements io.Writer and Fd() type fdWriter interface { io.Writer diff --git a/pkg/jyaml/jyaml.go b/pkg/jyaml/jyaml.go index 5476be33..ad4925b0 100644 --- a/pkg/jyaml/jyaml.go +++ b/pkg/jyaml/jyaml.go @@ -49,21 +49,21 @@ func MarshalYAML(v any) ([]byte, error) { } func Unmarshal[T any](object any) (T, error) { - var err error var data []byte - switch any(object).(type) { - case T: - return object.(T), nil - case []byte: - data = object.([]byte) + switch v := object.(type) { case string: - data = []byte(object.(string)) + data = []byte(v) + case []byte: + data = v + case T: + return v, nil default: - data, err = yaml.Marshal(object) + marshaled, err := yaml.Marshal(object) if err != nil { return *new(T), err } + data = marshaled } var result T @@ -75,21 +75,21 @@ func Unmarshal[T any](object any) (T, error) { } func UnmarshalStrict[T any](object any) (T, error) { - var err error var data []byte - switch any(object).(type) { - case T: - return object.(T), nil - case []byte: - data = object.([]byte) + switch v := object.(type) { case string: - data = []byte(object.(string)) + data = []byte(v) + case []byte: + data = v + case T: + return v, nil default: - data, err = yaml.Marshal(object) + marshaled, err := yaml.Marshal(object) if err != nil { return *new(T), err } + data = marshaled } var result T diff --git a/pkg/provider/aws/aws.go b/pkg/provider/aws/aws.go index 977a8d8a..8ef9e6be 100644 --- a/pkg/provider/aws/aws.go +++ b/pkg/provider/aws/aws.go @@ -23,7 +23,6 @@ import ( "github.com/NVIDIA/holodeck/api/holodeck/v1alpha1" "github.com/NVIDIA/holodeck/internal/logger" "github.com/NVIDIA/holodeck/pkg/jyaml" - "sigs.k8s.io/yaml" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ec2" @@ -167,37 +166,6 @@ func (p *Provider) unmarsalCache() (*AWS, error) { return aws, nil } -// dump writes the AWS struct to the cache file -func (p *Provider) dumpCache(aws *AWS) error { - env := p.Environment.DeepCopy() - env.Status.Properties = []v1alpha1.Properties{ - {Name: VpcID, Value: aws.Vpcid}, - {Name: SubnetID, Value: aws.Subnetid}, - {Name: InternetGwID, Value: aws.InternetGwid}, - {Name: InternetGatewayAttachment, Value: aws.InternetGatewayAttachment}, - {Name: RouteTable, Value: aws.RouteTable}, - {Name: SecurityGroupID, Value: aws.SecurityGroupid}, - {Name: InstanceID, Value: aws.Instanceid}, - {Name: PublicDnsName, Value: aws.PublicDnsName}, - } - - data, err := yaml.Marshal(env) - if err != nil { - return err - } - - err = os.WriteFile(p.cacheFile, data, 0644) - if err != nil { - return err - } - - // Update the environment object with the new properties - - p.Environment = env - - return nil -} - func (p *Provider) done() { p.log.Done <- struct{}{} p.log.Wg.Wait() diff --git a/pkg/provider/aws/create.go b/pkg/provider/aws/create.go index 5b274d36..18f1331f 100644 --- a/pkg/provider/aws/create.go +++ b/pkg/provider/aws/create.go @@ -31,40 +31,40 @@ import ( func (p *Provider) Create() error { cache := new(AWS) - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Creating AWS resources") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Creating AWS resources") //nolint:errcheck if err := p.createVPC(cache); err != nil { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating VPC") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating VPC") //nolint:errcheck return fmt.Errorf("error creating VPC: %v", err) } - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "VPC created") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "VPC created") //nolint:errcheck if err := p.createSubnet(cache); err != nil { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating subnet") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating subnet") //nolint:errcheck return fmt.Errorf("error creating subnet: %v", err) } - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Subnet created") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Subnet created") //nolint:errcheck if err := p.createInternetGateway(cache); err != nil { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating Internet Gateway") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating Internet Gateway") //nolint:errcheck return fmt.Errorf("error creating Internet Gateway: %v", err) } - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Internet Gateway created") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Internet Gateway created") //nolint:errcheck if err := p.createRouteTable(cache); err != nil { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating route table") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating route table") //nolint:errcheck return fmt.Errorf("error creating route table: %v", err) } - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Route Table created") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Route Table created") //nolint:errcheck if err := p.createSecurityGroup(cache); err != nil { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating security group") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating security group") //nolint:errcheck return fmt.Errorf("error creating security group: %v", err) } - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Security Group created") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Security Group created") //nolint:errcheck if err := p.createEC2Instance(cache); err != nil { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating EC2 instance") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating EC2 instance") //nolint:errcheck return fmt.Errorf("error creating EC2 instance: %v", err) } diff --git a/pkg/provider/aws/delete.go b/pkg/provider/aws/delete.go index 7492d1a2..0980c700 100644 --- a/pkg/provider/aws/delete.go +++ b/pkg/provider/aws/delete.go @@ -43,7 +43,7 @@ func (p *Provider) delete(cache *AWS) error { var err error // Delete the EC2 instance - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting EC2 instance") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting EC2 instance") //nolint:errcheck if cache.Instanceid == "" { p.log.Warning("No instance found to delete") } else { @@ -55,14 +55,14 @@ func (p *Provider) delete(cache *AWS) error { } if i == 2 { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Error deleting EC2 instance") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Error deleting EC2 instance") //nolint:errcheck return fmt.Errorf("error deleting EC2 instance: %v", err) } } } // Delete the VPC - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting VPC resources") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting VPC resources") //nolint:errcheck for i := 0; i < 3; i++ { err = p.deleteVPC(cache) if err == nil { @@ -70,7 +70,7 @@ func (p *Provider) delete(cache *AWS) error { } if i == 2 { - p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Error deleting VPC resources") + p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Error deleting VPC resources") //nolint:errcheck return fmt.Errorf("error deleting VPC resources: %v", err) } } @@ -124,7 +124,7 @@ func (p *Provider) deleteVPC(cache *AWS) error { // Delete the VPC p.log.Wg.Add(1) go p.log.Loading("Deleting VPC resources") - p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting VPC resources") + p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting VPC resources") //nolint:errcheck // Delete the subnet if cache.Subnetid == "" { p.log.Warning("No subnet found to delete") diff --git a/pkg/provider/aws/dryrun.go b/pkg/provider/aws/dryrun.go index 6f682f11..d7fbad9a 100644 --- a/pkg/provider/aws/dryrun.go +++ b/pkg/provider/aws/dryrun.go @@ -23,7 +23,7 @@ import ( func (p *Provider) DryRun() error { // Check if the desired instance type is supported in the region p.log.Wg.Add(1) - go p.log.Loading("Checking if instance type %s is supported in region %s", string(p.Spec.Instance.Type), p.Spec.Instance.Region) + go p.log.Loading("Checking if instance type %s is supported in region %s", p.Spec.Instance.Type, p.Spec.Instance.Region) err := p.checkInstanceTypes() if err != nil { p.fail() diff --git a/pkg/provider/aws/image.go b/pkg/provider/aws/image.go index cbb28870..3e5651db 100644 --- a/pkg/provider/aws/image.go +++ b/pkg/provider/aws/image.go @@ -179,5 +179,5 @@ func (p *Provider) checkInstanceTypes() error { } } - return fmt.Errorf("instance type %s is not supported in the current region %s", string(p.Spec.Instance.Type), p.Spec.Instance.Region) + return fmt.Errorf("instance type %s is not supported in the current region %s", p.Spec.Instance.Type, p.Spec.Instance.Region) } diff --git a/pkg/provider/aws/status.go b/pkg/provider/aws/status.go index f556ac5b..529d3fbd 100644 --- a/pkg/provider/aws/status.go +++ b/pkg/provider/aws/status.go @@ -180,7 +180,7 @@ func update(env *v1alpha1.Environment, cachePath string) error { } // write to file - err = os.WriteFile(cachePath, data, 0644) + err = os.WriteFile(cachePath, data, 0600) if err != nil { return err } diff --git a/pkg/provisioner/provisioner.go b/pkg/provisioner/provisioner.go index 8b9a62df..c0ae3827 100644 --- a/pkg/provisioner/provisioner.go +++ b/pkg/provisioner/provisioner.go @@ -205,7 +205,7 @@ func (p *Provisioner) createKindConfig(env v1alpha1.Environment) error { // Close the writing pipe and wait for the session to finish remoteFile.Close() - session.Wait() + session.Wait() // nolint:errcheck return nil } @@ -240,7 +240,7 @@ func connectOrDie(keyPath, userName, hostUrl string) (*ssh.Client, error) { Auth: []ssh.AuthMethod{ ssh.PublicKeys(signer), }, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), + HostKeyCallback: ssh.InsecureIgnoreHostKey(), // nolint:gosec } connectionFailed := false diff --git a/tests/common/common.go b/tests/common/common.go index 254c0dd1..6c9a5800 100644 --- a/tests/common/common.go +++ b/tests/common/common.go @@ -16,15 +16,18 @@ package common -import "math/rand" +import ( + "crypto/rand" + "encoding/hex" + "log" +) +// GenerateUID generates a secure random 8-character UID. func GenerateUID() string { - const charset = "abcdefghijklmnopqrstuvwxyz0123456789" - - b := make([]byte, 8) - for i := range b { - b[i] = charset[rand.Intn(len(charset))] + b := make([]byte, 4) // 4 bytes = 8 hex characters + _, err := rand.Read(b) + if err != nil { + log.Fatalf("failed to generate secure random UID: %v", err) } - - return string(b) + return hex.EncodeToString(b) }