|
541 | 541 | # required: false |
542 | 542 | # default: 'https://polaris.blackduck.com' |
543 | 543 | # type: string |
| 544 | + perform-wiz-scan: |
| 545 | + description: 'Perform Wiz CLI security scan on Docker image' |
| 546 | + required: false |
| 547 | + type: boolean |
| 548 | + default: false |
| 549 | + wiz-fail-build: |
| 550 | + description: 'Fail the build on Wiz policy violations' |
| 551 | + required: false |
| 552 | + type: boolean |
| 553 | + default: true |
| 554 | + wiz-fail-on-critical: |
| 555 | + description: 'Fail the pipeline if Wiz finds CRITICAL vulnerabilities' |
| 556 | + required: false |
| 557 | + type: boolean |
| 558 | + default: false |
| 559 | + wiz-fail-on-high: |
| 560 | + description: 'Fail the pipeline if Wiz finds HIGH vulnerabilities' |
| 561 | + required: false |
| 562 | + type: boolean |
| 563 | + default: false |
| 564 | + wiz-fail-on-medium: |
| 565 | + description: 'Fail the pipeline if Wiz finds MEDIUM vulnerabilities' |
| 566 | + required: false |
| 567 | + type: boolean |
| 568 | + default: false |
| 569 | + wiz-fail-on-low: |
| 570 | + description: 'Fail the pipeline if Wiz finds LOW vulnerabilities' |
| 571 | + required: false |
| 572 | + type: boolean |
| 573 | + default: false |
544 | 574 |
|
545 | 575 | env: |
546 | 576 | PRIMARY_APPLICATION: ${{ inputs.application }} # was 'default' # Custom repo property [primaryApplication]: chef360, automate, infra-server, habitat, supermarket, licensing, downloads, chef-client, inspec, chef-workstation (or derivatives like habitat-builder) |
@@ -976,159 +1006,142 @@ jobs: |
976 | 1006 | # fail-build: true |
977 | 1007 | # severity-cutoff: high |
978 | 1008 |
|
979 | | - run-grype-image: |
980 | | - name: 'Grype Docker image scan' |
981 | | - if: ${{ inputs.perform-grype-image-scan }} |
982 | | - uses: chef/common-github-actions/.github/workflows/grype.yml@main |
983 | | - needs: checkout |
984 | | - secrets: inherit |
985 | | - with: |
986 | | - fail-grype-on-high: ${{ inputs.grype-image-fail-on-high }} |
987 | | - fail-grype-on-critical: ${{ inputs.grype-image-fail-on-critical }} |
988 | | - grype-image-skip-aws: ${{ inputs.grype-image-skip-aws }} |
989 | | - |
990 | | - run-grype-hab-package-scan: |
991 | | - name: 'Grype scan Habitat packages from bldr.habitat.sh' |
992 | | - if: ${{ inputs.perform-grype-hab-scan == true }} |
993 | | - uses: chef/common-github-actions/.github/workflows/grype-hab-package-scan.yml@main |
994 | | - needs: checkout |
995 | | - secrets: inherit |
996 | | - with: |
997 | | - build_package: ${{ inputs.grype-hab-build-package }} |
998 | | - hab_origin: ${{ inputs.grype-hab-origin }} |
999 | | - hab_package: ${{ inputs.grype-hab-package }} |
1000 | | - hab_version: ${{ inputs.grype-hab-version }} |
1001 | | - hab_release: ${{ inputs.grype-hab-release }} |
1002 | | - hab_channel: ${{ inputs.grype-hab-channel }} |
1003 | | - hab_path: ${{ inputs.grype-hab-path }} |
1004 | | - scan-linux: ${{ inputs.grype-hab-scan-linux }} |
1005 | | - scan-windows: ${{ inputs.grype-hab-scan-windows }} |
1006 | | - scan-macos: ${{ inputs.grype-hab-scan-macos }} |
1007 | | - fail-grype-on-high: ${{ inputs.grype-fail-on-high }} |
1008 | | - fail-grype-on-critical: ${{ inputs.grype-fail-on-critical }} |
1009 | | - |
1010 | | - # run-srcclr: |
1011 | | - # if: ${{ inputs.perform-srcclr-scan == true }} |
1012 | | - # uses: chef/common-github-actions/.github/workflows/srcclr.yml@main |
1013 | | - # needs: run-scc |
1014 | | - |
1015 | | - # run-veracode-sca: |
1016 | | - # if: ${{ inputs.perform-veracode-sca-scan == true }} |
1017 | | - # uses: chef/common-github-actions/.github/workflows/veracode-sca.yml@main |
1018 | | - # needs: run-scc |
1019 | | - # secrets: inherit |
1020 | | - |
1021 | | - ci-build: |
1022 | | - name: 'Build/compilation and unit tests (CI)' |
1023 | | - if : ${{ inputs.build == true }} |
1024 | | - needs: checkout |
1025 | | - timeout-minutes: 40 # Maximum allowed minutes for GitHub-hosted runners (6 hours = 360 minutes) |
| 1009 | + build-docker-image: |
| 1010 | + name: 'Build Docker image for scanning' |
| 1011 | + if: ${{ inputs.perform-grype-image-scan || inputs.perform-wiz-scan }} |
1026 | 1012 | runs-on: ubuntu-latest |
1027 | | - # TODO: make this matrix strategy, and allow language compiler version overrides |
| 1013 | + needs: checkout |
| 1014 | + outputs: |
| 1015 | + image-tar: ${{ steps.save-image.outputs.image-tar }} |
1028 | 1016 | steps: |
1029 | | - - name: 'Build language: ${{ inputs.language }}' |
1030 | | - run: | |
1031 | | - echo "Building application in language ${{ env.GA_BUILD_LANGUAGE }}" |
1032 | | - echo " passed in with ${{ inputs.language }}" |
1033 | 1017 | - name: Checkout repository |
1034 | 1018 | uses: actions/checkout@v6 |
1035 | 1019 | with: |
1036 | 1020 | fetch-depth: 0 |
1037 | | - - name: Configure git for private Go modules |
1038 | | - if: inputs.language == 'go' |
| 1021 | + |
| 1022 | + - name: Configure git for private repos |
| 1023 | + run: git config --global url."https://${{ secrets.GH_TOKEN }}@github.com/".insteadOf "https://github.com/" |
| 1024 | + |
| 1025 | + - name: Build Docker image |
| 1026 | + id: build-image |
1039 | 1027 | env: |
1040 | | - GOPRIVATE: ${{ inputs.go-private-modules }} |
1041 | | - run: git config --global url."https://${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/" |
1042 | | - - name: 'Go build' |
1043 | | - if: ${{ inputs.language == 'go' && env.GA_BUILD_PROFILE == 'cli' }} |
1044 | | - continue-on-error: true |
1045 | | - # TODO: make this a matrix on WIndows/Mac/Linux |
1046 | | - # TODO: parameterize build output path |
1047 | | - run: | |
1048 | | - ls |
1049 | | - pwd |
1050 | | - go mod tidy |
1051 | | - go build -o ./bin/${{ env.REPO_NAME }} . |
1052 | | - - name: 'Go unit tests' |
1053 | | - if: ${{ inputs.language == 'go' && inputs.unit-tests == true && inputs.build-profile == 'cli' }} |
1054 | | - continue-on-error: true |
| 1028 | + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} |
1055 | 1029 | run: | |
1056 | | - go test -v ./... > ${{ inputs.unit-test-output-path }} |
| 1030 | + REPO_NAME=$(basename $(pwd)) |
1057 | 1031 |
|
1058 | | - # TODO: add unit-test-command-override if go test is not desired |
| 1032 | + if [ ! -f "Dockerfile" ]; then |
| 1033 | + echo "❌ No Dockerfile found - cannot build image for scanning" |
| 1034 | + exit 1 |
| 1035 | + fi |
1059 | 1036 |
|
1060 | | - - name: Upload test coverage artifact |
1061 | | - if: ${{ inputs.language == 'go' && inputs.unit-tests == true && inputs.build-profile == 'cli' }} |
1062 | | - uses: actions/upload-artifact@v4 |
1063 | | - # TODO: parameterize the unit test and coverage report names |
1064 | | - with: |
1065 | | - # Name of the artifact to upload. |
1066 | | - name: test-coverage.out |
1067 | | - # A file, directory or wildcard pattern that describes what to upload |
1068 | | - path: ${{ inputs.unit-test-output-path }} |
1069 | | - # run: go test -v -coverprofile="coverage.out" ./... and upload artifact! |
1070 | | - # - name: Build for Rust binary |
1071 | | - # if: ${{ env.GA_BUILD_LANGUAGE == 'rust' }} |
1072 | | - # run: echo 'hello world' |
1073 | | - # # cargo build --release --target-dir ./bin |
1074 | | - |
1075 | | - # - name: Build for Ruby binary |
1076 | | - # simple bundle install to generate gemlock(puts them in directory vendor/bundle, and uses actual gemspec for deployment to get multi-architecture ), then build gem |
1077 | | - # https://bundler.io/man/bundle-install.1.html |
1078 | | - - name: Set up Ruby # Fixed: Ruby setup was missing, causing "bundle: command not found" errors |
1079 | | - if: ${{ inputs.language == 'ruby' && inputs.build-profile == 'cli' }} |
1080 | | - uses: ruby/setup-ruby@v1 |
1081 | | - with: |
1082 | | - ruby-version: '3.4' |
1083 | | - bundler-cache: false |
| 1037 | + echo "Building Docker image for shared scanning..." |
1084 | 1038 |
|
1085 | | - - name: Configure Bundler for private Ruby gems |
1086 | | - if: ${{ inputs.language == 'ruby' && inputs.build-profile == 'cli' }} |
1087 | | - run: | |
1088 | | - if [ -z "${{ secrets.PRIVATE_ACCESS_KITCHEN_CHEF_ENTERPRISE }}" ]; then |
1089 | | - echo "Skipping: PRIVATE_ACCESS_KITCHEN_CHEF_ENTERPRISE secret not configured or not in scope" |
1090 | | - exit 0 |
1091 | | - fi |
1092 | | - bundle config set --local github.com "x-access-token:${{ secrets.PRIVATE_ACCESS_KITCHEN_CHEF_ENTERPRISE }}" |
| 1039 | + # Strategy 1: Check for build-docker.sh script (e.g., dsm-erchef) |
| 1040 | + if [ -f "build-docker.sh" ]; then |
| 1041 | + echo "Found build-docker.sh script - using it to build images" |
| 1042 | + chmod +x build-docker.sh |
| 1043 | + GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" ./build-docker.sh |
1093 | 1044 |
|
1094 | | - - name: 'Ruby build' |
1095 | | - if: ${{ inputs.language == 'ruby' && inputs.build-profile == 'cli' }} |
1096 | | - continue-on-error: true |
1097 | | - run: | |
1098 | | - mkdir -p vendor |
1099 | | - if [ -f "Gemfile.lock" ]; then |
1100 | | - bundle install --deployment |
| 1045 | + IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "^<none>" | head -1) |
| 1046 | +
|
| 1047 | + if [ -z "$IMAGE" ]; then |
| 1048 | + echo "⚠️ No image found with prefix ${REPO_NAME} after build-docker.sh" |
| 1049 | + echo "Checking for any recently built images..." |
| 1050 | + IMAGE=$(docker images --format "{{.CreatedAt}}\t{{.Repository}}:{{.Tag}}" | sort -r | head -1 | cut -f2) |
| 1051 | + fi |
| 1052 | + # Strategy 2: Check for Makefile with compose-build target |
| 1053 | + elif [ -f "Makefile" ] && grep -q "^compose-build:" Makefile; then |
| 1054 | + echo "Using Makefile compose-build target with GITHUB_TOKEN" |
| 1055 | + export GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" |
| 1056 | + |
| 1057 | + # Record image IDs before build to detect newly built images |
| 1058 | + BEFORE_IDS=$(docker images -q --no-trunc | sort) |
| 1059 | + |
| 1060 | + make compose-build |
| 1061 | +
|
| 1062 | + echo "Detecting built image..." |
| 1063 | + # Find newly created images by comparing before/after image IDs |
| 1064 | + AFTER_IDS=$(docker images -q --no-trunc | sort) |
| 1065 | + NEW_IDS=$(comm -13 <(echo "$BEFORE_IDS") <(echo "$AFTER_IDS")) |
| 1066 | + |
| 1067 | + if [ -n "$NEW_IDS" ]; then |
| 1068 | + for id in $NEW_IDS; do |
| 1069 | + # Use docker inspect instead of --filter (compatible with all Docker versions) |
| 1070 | + IMAGE=$(docker inspect --format '{{index .RepoTags 0}}' "$id" 2>/dev/null || true) |
| 1071 | + [ -n "$IMAGE" ] && [ "$IMAGE" != "<none>:<none>" ] && break |
| 1072 | + IMAGE="" |
| 1073 | + done |
| 1074 | + fi |
| 1075 | +
|
| 1076 | + if [ -z "$IMAGE" ]; then |
| 1077 | + echo "No new image detected by ID comparison, falling back to repo name match" |
| 1078 | + IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "<none>" | head -1) |
| 1079 | + fi |
| 1080 | +
|
| 1081 | + if [ -z "$IMAGE" ]; then |
| 1082 | + echo "⚠️ No image found matching ${REPO_NAME}, using most recent non-runner image" |
| 1083 | + IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^<none>" | grep -v "^ghcr.io/github/" | grep -v "^ghcr.io/dependabot/" | head -1) |
| 1084 | + fi |
| 1085 | + # Strategy 3: Fallback to standard docker build |
1101 | 1086 | else |
1102 | | - echo "No Gemfile.lock found, creating it now" |
1103 | | - bundle install --path vendor/bundle # Fixed: Removed --deployment flag when lockfile doesn't exist |
| 1087 | + echo "Using standard docker build with GITHUB_TOKEN build arg" |
| 1088 | + docker build --build-arg GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" -t "${REPO_NAME}:latest" . |
| 1089 | + IMAGE="${REPO_NAME}:latest" |
1104 | 1090 | fi |
1105 | | - bundle exec rake build |
1106 | | - # this does not work on all repos - chef-telemetry needs bundle install to generate gemfile.lock, but chef-cli does not commit gemfile.lock and needs bundle install to generate it at runtime - add flag to control whether bundle install is run in ci-build or language-specific checks |
1107 | | - # TODO: detect if rakefile exists, else do bundler default |
1108 | | - - name: 'Ruby unit tests' |
1109 | | - if: ${{ inputs.language == 'ruby' && inputs.unit-tests == true && inputs.build-profile == 'cli' }} |
1110 | | - continue-on-error: true |
| 1091 | +
|
| 1092 | + if [ -z "$IMAGE" ]; then |
| 1093 | + echo "❌ No Docker image found after build" |
| 1094 | + exit 1 |
| 1095 | + fi |
| 1096 | +
|
| 1097 | + echo "Built image: $IMAGE" |
| 1098 | + echo "IMAGE=$IMAGE" >> "$GITHUB_OUTPUT" |
| 1099 | +
|
| 1100 | + - name: Save Docker image as tar |
| 1101 | + id: save-image |
1111 | 1102 | run: | |
1112 | | - echo "Running Ruby unit tests with output to ${{ inputs.unit-test-output-path }}" |
1113 | | - # bundle exec rake spec --trace > ${{ inputs.unit-test-output-path }} |
| 1103 | + IMAGE="${{ steps.build-image.outputs.IMAGE }}" |
| 1104 | + TAR_FILE="docker-image.tar" |
| 1105 | + |
| 1106 | + echo "Saving Docker image $IMAGE to $TAR_FILE..." |
| 1107 | + docker save "$IMAGE" -o "$TAR_FILE" |
| 1108 | + |
| 1109 | + echo "Image saved successfully" |
| 1110 | + echo "image-tar=$TAR_FILE" >> "$GITHUB_OUTPUT" |
| 1111 | +
|
| 1112 | + - name: Upload Docker image artifact |
| 1113 | + uses: actions/upload-artifact@v4 |
| 1114 | + with: |
| 1115 | + name: docker-image-${{ github.event.repository.name }} |
| 1116 | + path: docker-image.tar |
| 1117 | + retention-days: 1 |
| 1118 | + |
| 1119 | + run-grype-image: |
| 1120 | + name: 'Grype Docker image scan' |
| 1121 | + if: ${{ inputs.perform-grype-image-scan }} |
| 1122 | + uses: chef/common-github-actions/.github/workflows/grype.yml@grype-wiz |
| 1123 | + needs: [checkout, build-docker-image] |
| 1124 | + secrets: inherit |
| 1125 | + with: |
| 1126 | + fail-grype-on-high: ${{ inputs.grype-image-fail-on-high }} |
| 1127 | + fail-grype-on-critical: ${{ inputs.grype-image-fail-on-critical }} |
| 1128 | + grype-image-skip-aws: ${{ inputs.grype-image-skip-aws }} |
| 1129 | + prebuilt-image-tar: docker-image.tar |
| 1130 | + |
| 1131 | + run-wiz-scan: |
| 1132 | + name: 'Wiz CLI security scan' |
| 1133 | + if: ${{ inputs.perform-wiz-scan == true }} |
| 1134 | + uses: chef/common-github-actions/.github/workflows/wiz.yml@grype-wiz |
| 1135 | + needs: [checkout, build-docker-image] |
| 1136 | + with: |
| 1137 | + fail-build: ${{ inputs.wiz-fail-build }} |
| 1138 | + fail-on-critical: ${{ inputs.wiz-fail-on-critical }} |
| 1139 | + fail-on-high: ${{ inputs.wiz-fail-on-high }} |
| 1140 | + fail-on-medium: ${{ inputs.wiz-fail-on-medium }} |
| 1141 | + fail-on-low: ${{ inputs.wiz-fail-on-low }} |
| 1142 | + prebuilt-image-tar: docker-image.tar |
| 1143 | + secrets: inherit |
1114 | 1144 |
|
1115 | | - # - name: Configure git for private modules |
1116 | | - # env: |
1117 | | - # GOPRIVATE: github.com/progress-platform-services/* |
1118 | | - # run: git config --global url."https://${{ secrets.GH_TOKEN }}@github.com/".insteadOf "https://github.com/" |
1119 | | - |
1120 | | - # TODO: dynamic version detection stepswith new flags ${{ detect-version-source-type: 'none' # options include "none" (do not detect), "file", "github-tag" or "github-release" |
1121 | | - # AND ${{ detect-version-source-parameter: '' # use for file name}} |
1122 | | - # version: ${{ github.workflow.env.APP_VERSION }} |
1123 | | - # version: ${{ needs.set-app-version.outputs.app-version }} |
1124 | | - |
1125 | | - # if you have a version file, you can read it in to an environment variable with |
1126 | | - # - name: Set variables |
1127 | | - # run: | |
1128 | | - # VER=$(cat VERSION) |
1129 | | - # echo "VERSION=$VER" >> $GITHUB_ENV |
1130 | | - # then ${{ env.VERSION }} |
1131 | | - |
1132 | 1145 | set-application-version: |
1133 | 1146 | runs-on: ubuntu-latest |
1134 | 1147 | name: 'Detect SBOM version for application' |
|
0 commit comments