diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22afda9..4e5b715 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,10 +31,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c with: go-version-file: "go.mod" cache: true @@ -46,7 +46,7 @@ jobs: run: go mod verify - name: Run golangci-lint - uses: golangci/golangci-lint-action@v8 + uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee with: version: ${{ env.GOLANGCI_VERSION }} @@ -55,10 +55,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c with: go-version-file: "go.mod" cache: true @@ -80,16 +80,16 @@ jobs: needs: [lint, test] steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 with: fetch-depth: 0 # Fetch all history for proper tagging - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 - name: Log in to Docker Hub if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -124,7 +124,7 @@ jobs: fi - name: Build and push Docker image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf with: context: . file: ./Dockerfile diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c7c703c..1b3f823 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,11 +2,11 @@ name: "CodeQL Analysis" on: push: - branches: [ main, master ] + branches: [main, master] pull_request: - branches: [ main, master ] + branches: [main, master] schedule: - - cron: '0 6 * * 1' # Run every Monday at 6 AM UTC + - cron: "0 6 * * 1" # Run every Monday at 6 AM UTC jobs: analyze: @@ -20,39 +20,39 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'go' ] + language: ["go"] steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Set up Go - if: matrix.language == 'go' - uses: actions/setup-go@v6 - with: - go-version-file: "go.mod" - cache: true - - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - queries: security-extended,security-and-quality - - - name: Download dependencies - if: matrix.language == 'go' - run: go mod download - - - name: Generate manifests and code - if: matrix.language == 'go' - run: | - make manifests - make generate - - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:${{matrix.language}}" + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 + + - name: Set up Go + if: matrix.language == 'go' + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c + with: + go-version-file: "go.mod" + cache: true + + - name: Initialize CodeQL + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + with: + languages: ${{ matrix.language }} + queries: security-extended,security-and-quality + + - name: Download dependencies + if: matrix.language == 'go' + run: go mod download + + - name: Generate manifests and code + if: matrix.language == 'go' + run: | + make manifests + make generate + + - name: Autobuild + uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 92dc8b8..a9c4e8a 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -2,9 +2,9 @@ name: E2E Tests on: push: - branches: [ main, master ] + branches: [main, master] pull_request: - branches: [ main, master ] + branches: [main, master] workflow_dispatch: # Allow manual triggering jobs: @@ -12,60 +12,60 @@ jobs: name: End-to-End Tests runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v6 + - name: Checkout code + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: "go.mod" - cache: true + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c + with: + go-version-file: "go.mod" + cache: true - - name: Download dependencies - run: go mod download + - name: Download dependencies + run: go mod download - - name: Set up Kind - uses: helm/kind-action@v1.14.0 - with: - version: v0.20.0 - kubectl_version: v1.30.0 - cluster_name: kind + - name: Set up Kind + uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc + with: + version: v0.20.0 + kubectl_version: v1.30.0 + cluster_name: kind - - name: Wait for cluster to be ready - run: | - kubectl cluster-info - kubectl wait --for=condition=Ready nodes --all --timeout=300s + - name: Wait for cluster to be ready + run: | + kubectl cluster-info + kubectl wait --for=condition=Ready nodes --all --timeout=300s - - name: Generate manifests and code - run: | - make manifests - make generate + - name: Generate manifests and code + run: | + make manifests + make generate - - name: Build manager binary - run: make build + - name: Build manager binary + run: make build - - name: Build Docker image - run: | - docker build -t controller:latest . + - name: Build Docker image + run: | + docker build -t controller:latest . - - name: Load image into Kind - run: | - kind load docker-image controller:latest + - name: Load image into Kind + run: | + kind load docker-image controller:latest - - name: Install CRDs - run: make install + - name: Install CRDs + run: make install - # we can't run e2e tests without a containerized storagegrid instance - # if you work at NetApp and have access to a StorageGrid docker license, please contact us to help set this up - # - name: Run E2E tests - # run: make test-e2e + # we can't run e2e tests without a containerized storagegrid instance + # if you work at NetApp and have access to a StorageGrid docker license, please contact us to help set this up + # - name: Run E2E tests + # run: make test-e2e - - name: Collect logs on failure - if: failure() - run: | - echo "=== Cluster Info ===" - kubectl cluster-info dump - echo "=== All Pod Logs ===" - kubectl logs --all-containers=true --prefix=true --previous=false -l app.kubernetes.io/name=storagegrid-operator || echo "No operator pods found" - echo "=== All Events ===" - kubectl get events --all-namespaces --sort-by='.lastTimestamp' + - name: Collect logs on failure + if: failure() + run: | + echo "=== Cluster Info ===" + kubectl cluster-info dump + echo "=== All Pod Logs ===" + kubectl logs --all-containers=true --prefix=true --previous=false -l app.kubernetes.io/name=storagegrid-operator || echo "No operator pods found" + echo "=== All Events ===" + kubectl get events --all-namespaces --sort-by='.lastTimestamp' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 45b7966..acbb541 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Release on: push: tags: - - 'v*' + - "v*" release: types: [published] @@ -20,110 +20,99 @@ jobs: packages: write steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: "go.mod" - cache: true - - - name: Download dependencies - run: go mod download - - - name: Generate manifests and code - run: | - make manifests - make generate - - - name: Log in to Container Registry - uses: docker/login-action@v4 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and push Docker image - uses: docker/build-push-action@v7 - with: - context: . - file: ./Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@master - with: - image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} - format: 'sarif' - output: 'trivy-results.sarif' - - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v4 - if: always() - with: - sarif_file: 'trivy-results.sarif' + - name: Checkout code + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c + with: + go-version-file: "go.mod" + cache: true + + - name: Download dependencies + run: go mod download + + - name: Generate manifests and code + run: | + make manifests + make generate + + - name: Log in to Container Registry + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 + + - name: Build and push Docker image + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} + format: "sarif" + output: "trivy-results.sarif" + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + if: always() + with: + sarif_file: "trivy-results.sarif" build-installer: name: Build Installer YAML runs-on: ubuntu-latest needs: build-and-push-image steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: "go.mod" - cache: true - - - name: Download dependencies - run: go mod download - - - name: Extract version from tag - id: version - run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT - - - name: Generate installer YAML - run: | - export IMG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:v${{ steps.version.outputs.VERSION }}" - make build-installer - - - name: Upload installer artifact - uses: actions/upload-artifact@v7 - with: - name: installer-yaml - path: dist/install.yaml - retention-days: 90 - - - name: Attach installer to release - if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: dist/install.yaml - asset_name: install.yaml - asset_content_type: text/yaml + - name: Checkout code + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c + with: + go-version-file: "go.mod" + cache: true + + - name: Download dependencies + run: go mod download + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Generate installer YAML + run: | + export IMG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:v${{ steps.version.outputs.VERSION }}" + make build-installer + + - name: Upload installer artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: installer-yaml + path: dist/install.yaml + retention-days: 90 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index e7fbcfe..739f608 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -3,43 +3,43 @@ name: Validate Workflows on: push: paths: - - '.github/workflows/**' + - ".github/workflows/**" pull_request: paths: - - '.github/workflows/**' + - ".github/workflows/**" jobs: validate: name: Validate GitHub Actions Workflows runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v6 + - name: Checkout code + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 - - name: Validate workflow files - run: | - echo "Checking workflow syntax..." - for workflow in .github/workflows/*.yml .github/workflows/*.yaml; do - if [ -f "$workflow" ]; then - echo "Validating $workflow" - # Basic YAML syntax check - python3 -c "import yaml; yaml.safe_load(open('$workflow'))" - echo "✓ $workflow is valid YAML" + - name: Validate workflow files + run: | + echo "Checking workflow syntax..." + for workflow in .github/workflows/*.yml .github/workflows/*.yaml; do + if [ -f "$workflow" ]; then + echo "Validating $workflow" + # Basic YAML syntax check + python3 -c "import yaml; yaml.safe_load(open('$workflow'))" + echo "✓ $workflow is valid YAML" + fi + done + + - name: Check for common issues + run: | + echo "Checking for common workflow issues..." + + # Check for hardcoded secrets (excluding examples) + if grep -r "ghp_\|github_pat_" .github/workflows/ || true; then + echo "⚠️ Warning: Potential hardcoded tokens found" + fi + + # Check for uses of deprecated actions + if grep -r "actions/checkout@v[12]" .github/workflows/ || true; then + echo "⚠️ Warning: Deprecated checkout action version found" fi - done - - name: Check for common issues - run: | - echo "Checking for common workflow issues..." - - # Check for hardcoded secrets (excluding examples) - if grep -r "ghp_\|github_pat_" .github/workflows/ || true; then - echo "⚠️ Warning: Potential hardcoded tokens found" - fi - - # Check for uses of deprecated actions - if grep -r "actions/checkout@v[12]" .github/workflows/ || true; then - echo "⚠️ Warning: Deprecated checkout action version found" - fi - - echo "Validation complete!" + echo "Validation complete!" diff --git a/internal/controller/s3policies/common.go b/internal/controller/s3policies/common.go index 546de84..f07814e 100644 --- a/internal/controller/s3policies/common.go +++ b/internal/controller/s3policies/common.go @@ -68,7 +68,6 @@ func policyInUse(ctx context.Context, k8sclient client.Client, policyName string log := log.FromContext(ctx).WithValues("function", "policyInUse") key := BuildPolicyKey(policyKind, policyNamespace, policyName) - var consumers []string // Check S3Access references. accessList := &s3v1alpha1.S3AccessList{} @@ -80,6 +79,7 @@ func policyInUse(ctx context.Context, k8sclient client.Client, policyName string return true, []string{} } + consumers := []string{} for _, access := range accessList.Items { consumers = append(consumers, fmt.Sprintf("S3Access/%s/%s", access.Namespace, access.Name)) } @@ -90,19 +90,20 @@ func policyInUse(ctx context.Context, k8sclient client.Client, policyName string if policyKind == "S3Policy" && policyNamespace != "" { listOpts = append(listOpts, client.InNamespace(policyNamespace)) } - if err := k8sclient.List(ctx, bucketList, listOpts...); client.IgnoreNotFound(err) != nil { + err = k8sclient.List(ctx, bucketList, listOpts...) + if client.IgnoreNotFound(err) != nil { log.Error(err, "Failed to list S3Buckets for policy", "policyKey", key) return true, []string{} } - for _, bucket := range bucketList.Items { - for _, binding := range bucket.Spec.BucketPolicies { + for i := range bucketList.Items { + for _, binding := range bucketList.Items[i].Spec.BucketPolicies { refKind := binding.PolicyRef.Kind if refKind == "" { refKind = "GlobalS3Policy" } if refKind == policyKind && binding.PolicyRef.Name == policyName { - consumers = append(consumers, fmt.Sprintf("S3Bucket/%s/%s", bucket.Namespace, bucket.Name)) + consumers = append(consumers, fmt.Sprintf("S3Bucket/%s/%s", bucketList.Items[i].Namespace, bucketList.Items[i].Name)) break } }