-
Notifications
You must be signed in to change notification settings - Fork 56
Improve Chef Supermarket workflow with inline SBOM generation and fixes #848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Adding Keeper-Chef Integration
Added ruby to resuable sbom, updated secrets, updated knife commands …
runs-on: ubuntu-latest | ||
outputs: | ||
version: ${{ steps.extract-version.outputs.version }} | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Extract version from metadata.rb | ||
id: extract-version | ||
working-directory: ./integration/keeper_secrets_manager_chef/cookbooks/keeper_secrets_manager | ||
run: | | ||
echo "Detecting Chef cookbook version..." | ||
if [ -f "metadata.rb" ]; then | ||
VERSION=$(grep "^version" "metadata.rb" | awk '{print $2}' | tr -d "'\"") | ||
echo "Detected version: ${VERSION}" | ||
else | ||
VERSION="1.0.0" | ||
echo "Could not detect version, using default: ${VERSION}" | ||
fi | ||
echo "version=${VERSION}" >> $GITHUB_OUTPUT | ||
|
||
|
||
generate-and-upload-sbom: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
To fix this issue, we should introduce a permissions
block at the workflow root (near the top of the file, after the name
and on
keys), specifying only the permissions needed for the workflow. For most workflows that do not require write access to repository contents, the minimal starting point is contents: read
. You should review the jobs to see if they need additional permissions (e.g., to create or update pull requests, upload artifacts, etc.), but as a minimal improvement we can add permissions: contents: read
. This block should be added to lines immediately after the name
and on
keys. No changes are needed elsewhere in the shown code.
-
Copy modified lines R5-R7
@@ -2,6 +2,9 @@ | ||
on: | ||
workflow_dispatch: | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
get-version: | ||
runs-on: ubuntu-latest |
needs: get-version | ||
runs-on: ubuntu-latest | ||
|
||
defaults: | ||
run: | ||
working-directory: ./integration/keeper_secrets_manager_chef/cookbooks/keeper_secrets_manager | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: '3.2.4' | ||
|
||
- name: Install cookbook dependencies into vendor directory | ||
run: | | ||
echo "Installing gem dependencies for SBOM generation..." | ||
gem install bundler | ||
|
||
# Create Gemfile if it doesn't exist (for Chef cookbooks) | ||
if [ ! -f "Gemfile" ]; then | ||
cat > Gemfile << 'EOF' | ||
source 'https://rubygems.org' | ||
|
||
gem 'chef', '>= 16.0' | ||
gem 'chefspec' | ||
gem 'rspec' | ||
gem 'cookstyle' | ||
EOF | ||
fi | ||
|
||
# Install all dependencies into vendor/bundle | ||
echo "Installing dependencies into vendor/bundle..." | ||
bundle install --path vendor/bundle | ||
|
||
echo "Installed gems:" | ||
bundle list | ||
|
||
- name: Generate and publish SBOM | ||
env: | ||
MANIFEST_TOKEN: ${{ secrets.MANIFEST_TOKEN }} | ||
run: | | ||
# Install tools (matching versions from master branch) | ||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin v1.18.1 | ||
curl -sSfL https://raw.githubusercontent.com/manifest-cyber/cli/main/install.sh | sh -s -- -b /usr/local/bin v0.18.3 | ||
|
||
# Create temp directory for scanning | ||
SCAN_DIR="${{ runner.temp }}/chef-scan" | ||
mkdir -p "$SCAN_DIR" | ||
|
||
# Copy cookbook and vendor directory (with all gem dependencies) | ||
echo "Copying cookbook files to scan directory..." | ||
cp -r . "$SCAN_DIR/" | ||
|
||
# Generate and publish SBOM from scan directory | ||
cd "$SCAN_DIR" | ||
manifest sbom . \ | ||
--generator=syft \ | ||
--name=keeper-secrets-manager-chef \ | ||
--version=${{ needs.get-version.outputs.version }} \ | ||
--output=spdx-json \ | ||
--file=sbom.json \ | ||
--api-key=${MANIFEST_TOKEN} \ | ||
--publish=true \ | ||
--asset-label=application,sbom-generated,ruby,chef,cookbook,ksm,integration,secrets-manager | ||
|
||
# Move SBOM back to working directory | ||
mv sbom.json "${{ github.workspace }}/integration/keeper_secrets_manager_chef/cookbooks/keeper_secrets_manager/" | ||
|
||
- name: Upload SBOM artifact | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: sbom-keeper-secrets-manager-chef-${{ needs.get-version.outputs.version }} | ||
path: ./integration/keeper_secrets_manager_chef/cookbooks/keeper_secrets_manager/sbom.json | ||
retention-days: 90 | ||
|
||
|
||
publish-chef-supermarket: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
To fix the problem, we need to add an explicit permissions
block at the workflow level to set the least privilege needed for all jobs. This block should be added directly after the name:
and on:
keys (before the jobs:
key) in .github/workflows/publish.chefsupermaket.yml
. The recommended minimal permissions setting is contents: read
, unless the workflow needs to perform actions that require further permissions (such as pushing code, opening issues, publishing releases, etc.), which is not apparent in this workflow. No new imports or methods are required, just a YAML configuration change. Ensure correct indentation and placement within the workflow file.
-
Copy modified lines R5-R7
@@ -2,6 +2,9 @@ | ||
on: | ||
workflow_dispatch: | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
get-version: | ||
runs-on: ubuntu-latest |
needs: generate-and-upload-sbom | ||
runs-on: ubuntu-latest | ||
environment: prod | ||
timeout-minutes: 20 | ||
|
||
defaults: | ||
run: | ||
working-directory: ./integration/keeper_secrets_manager_chef/cookbooks/keeper_secrets_manager | ||
|
||
steps: | ||
- name: Get the source code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: '3.2.4' | ||
bundler-cache: false | ||
|
||
- name: Retrieve secrets from KSM | ||
id: ksmsecrets | ||
uses: Keeper-Security/ksm-action@master | ||
with: | ||
keeper-secret-config: ${{ secrets.KSM_CHEF_SUPERMARKET_CONFIG }} | ||
secrets: | | ||
${{ secrets.CHEF_SUPERMARKET_RECORD_UID }}/field/password > CHEF_SUPERMARKET_API_KEY | ||
|
||
- name: Get current version and validate | ||
id: version | ||
run: | | ||
if [[ -f "metadata.rb" ]]; then | ||
VERSION=$(grep "^version" metadata.rb | awk '{print $2}' | tr -d "'\"") | ||
echo "current_version=$VERSION" >> $GITHUB_OUTPUT | ||
echo "Current version: $VERSION" | ||
else | ||
echo "Error: metadata.rb not found" | ||
exit 1 | ||
fi | ||
|
||
- name: Check if version already exists on Chef Supermarket | ||
env: | ||
VERSION: ${{ steps.version.outputs.current_version }} | ||
run: | | ||
echo "Checking if version $VERSION exists on Supermarket..." | ||
HTTP_CODE=$(curl -s -o /tmp/supermarket_response.json -w "%{http_code}" \ | ||
"https://supermarket.chef.io/api/v1/cookbooks/keeper_secrets_manager/versions/${VERSION}") | ||
|
||
if [ "$HTTP_CODE" = "200" ]; then | ||
# Version exists | ||
echo "Error: Version $VERSION already exists on Chef Supermarket!" | ||
cat /tmp/supermarket_response.json | ||
rm -f /tmp/supermarket_response.json | ||
exit 1 | ||
elif [ "$HTTP_CODE" = "404" ]; then | ||
# Version doesn't exist (expected) | ||
echo "Version $VERSION is available for publishing" | ||
rm -f /tmp/supermarket_response.json | ||
else | ||
# Unexpected error | ||
echo "Warning: Unexpected HTTP response code: $HTTP_CODE" | ||
cat /tmp/supermarket_response.json | ||
rm -f /tmp/supermarket_response.json | ||
echo "Proceeding with caution..." | ||
fi | ||
|
||
- name: Install Chef Workstation | ||
run: | | ||
echo "Installing Chef Workstation..." | ||
curl -L https://omnitruck.chef.io/install.sh -o /tmp/install.sh | ||
sudo bash /tmp/install.sh -P chef-workstation -v 24.6.1019 | ||
rm /tmp/install.sh | ||
chef --version | ||
|
||
- name: Install gem dependencies | ||
run: | | ||
echo "Installing gem dependencies..." | ||
gem install bundler | ||
gem install chefspec rspec cookstyle | ||
|
||
- name: Install cookbook dependencies | ||
run: | | ||
echo "Installing cookbook dependencies via Berkshelf..." | ||
berks install || echo "No Berkshelf dependencies or Berksfile not found" | ||
|
||
- name: Validate cookbook metadata | ||
run: | | ||
echo "Validating cookbook metadata..." | ||
if [ ! -f "metadata.rb" ]; then | ||
echo "Error: metadata.rb not found!" | ||
exit 1 | ||
fi | ||
|
||
# Check required metadata fields | ||
for field in name maintainer license version; do | ||
if ! grep -q "^${field}" metadata.rb; then | ||
echo "Error: Required field '${field}' not found in metadata.rb" | ||
exit 1 | ||
fi | ||
done | ||
|
||
echo "Cookbook metadata validation passed" | ||
|
||
- name: Run linting (Cookstyle) | ||
run: | | ||
echo "Running cookstyle..." | ||
cookstyle || exit 1 | ||
|
||
- name: Run ChefSpec tests | ||
run: | | ||
echo "Running ChefSpec tests..." | ||
rspec || exit 1 | ||
|
||
- name: Publish to Chef Supermarket | ||
env: | ||
CHEF_SUPERMARKET_API_KEY: ${{ steps.ksmsecrets.outputs.CHEF_SUPERMARKET_API_KEY }} | ||
VERSION: ${{ steps.version.outputs.current_version }} | ||
run: | | ||
echo "Publishing to Chef Supermarket..." | ||
knife supermarket share keeper_secrets_manager "Utilities" \ | ||
--supermarket-site https://supermarket.chef.io \ | ||
--cookbook-path .. | ||
|
||
echo "Successfully published to Chef Supermarket!" | ||
|
||
- name: Create release summary | ||
env: | ||
VERSION: ${{ steps.version.outputs.current_version }} | ||
run: | | ||
echo "## Chef Cookbook Published Successfully!" >> $GITHUB_STEP_SUMMARY | ||
echo "**Version:** $VERSION" >> $GITHUB_STEP_SUMMARY | ||
echo "**Cookbook:** keeper_secrets_manager" >> $GITHUB_STEP_SUMMARY | ||
echo "**Supermarket URL:** https://supermarket.chef.io/cookbooks/keeper_secrets_manager" >> $GITHUB_STEP_SUMMARY | ||
echo "" >> $GITHUB_STEP_SUMMARY | ||
echo "### Validation Results" >> $GITHUB_STEP_SUMMARY | ||
echo "- Cookstyle: Passed" >> $GITHUB_STEP_SUMMARY | ||
echo "- ChefSpec Tests: Passed" >> $GITHUB_STEP_SUMMARY | ||
echo "- Cookbook Build: Successful" >> $GITHUB_STEP_SUMMARY | ||
echo "- Supermarket Publish: Successful" >> $GITHUB_STEP_SUMMARY |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
To resolve this issue, the workflow should be updated to explicitly specify the minimal required permissions for the GITHUB_TOKEN
. This can be done at the workflow root to apply to all jobs, or scoped per job if required. For most publishing and artifact jobs, minimal permissions such as contents: read
are sufficient unless steps require more (e.g., creating releases). The ideal first step is to add permissions: contents: read
at the top level, but, if a specific job requires more, this should be indicated on a per-job basis. For the shown workflow, adding the block at the top (after name:
and before on:
) is clear and effective. No other code changes are required.
-
Copy modified lines R2-R3
@@ -1,4 +1,6 @@ | ||
name: Publish to Chef Supermarket | ||
permissions: | ||
contents: read | ||
on: | ||
workflow_dispatch: | ||
|
# -------------------- Logging & Custom Exceptions -------------------- | ||
|
||
def log_message(level, message): | ||
print(f"[{level}] KEEPER: {message}", file=sys.stderr) |
Check failure
Code scanning / CodeQL
Clear-text logging of sensitive information High
sensitive data (secret)
This expression logs
sensitive data (secret)
This expression logs
sensitive data (secret)
This expression logs
sensitive data (secret)
This expression logs
sensitive data (secret)
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
To fix this problem:
- Review all usage of
log_message()
where sensitive data (here,keeper_notation
, originating from user or config input) is included in log output. - Specifically, in
process_secret_notation
, sanitize error messages to avoid including secret notation strings. - Update the log statement on line 270 to only report a generic failure, optionally including a reference index (from the current loop in
process_secrets_array
) or generic labels, without the actualkeeper_notation
value. - If broader context is needed for debugging, consider logging only anonymized or hashed references, or a generic error code.
Required changes:
- Replace line 270’s log statement to avoid exposing
keeper_notation
. - Possibly update
process_secrets_array
to include the index for more helpful (but still safe) debugging, but avoid any sensitive information. - No new imports or dependencies needed.
-
Copy modified lines R270-R271
@@ -267,7 +267,8 @@ | ||
cumulative_output[output_name] = value | ||
|
||
except Exception as e: | ||
log_message("ERROR", f"Failed to process keeper notation '{keeper_notation}': {e}") | ||
# Avoid logging potentially sensitive Keeper notation | ||
log_message("ERROR", f"Failed to process keeper notation due to: {e}") | ||
raise | ||
|
||
def process_secrets_array(sm, secrets_array, cumulative_output): |
env_path = os.path.join(Constants.DEFAULT_PATH, Constants.ENV_FILE) | ||
os.makedirs(Constants.DEFAULT_PATH, exist_ok=True) | ||
with open(env_path, "a") as env_file: | ||
env_file.write(f'export {output_name}="{value}"\n') |
Check failure
Code scanning / CodeQL
Clear-text storage of sensitive information High
sensitive data (secret)
This expression stores
sensitive data (secret)
This expression stores
sensitive data (secret)
This expression stores
sensitive data (secret)
This expression stores
sensitive data (secret)
TEMPORARY: This commit adds a push trigger to enable workflow testing. This trigger should be REMOVED before final merge to master. The push trigger allows GitHub Actions to recognize and execute the workflow on the chef/workflow-update-sbom-inline branch for validation.
Removed the temporary push trigger that was added for initial testing. Workflow can now be triggered manually via GitHub Actions UI using workflow_dispatch.
Summary
This PR improves the Chef Supermarket publishing workflow with critical bug fixes and replaces the reusable SBOM workflow with inline implementation.
Note: This PR builds on the work from PR #771. Created primarily for workflow testing purposes. Final changes will be integrated into the forked branch
metron-labs:release/integration/chef/v1.0.0
.Critical Fixes
knife supermarket share
command--cookbook-path .
to--cookbook-path ..
(must point to parent directory)grep "version"
togrep "^version"
to avoid matchingchef_version
Enhancements
vendor/bundle
for comprehensive SBOM scanningSBOM Implementation Details
The inline SBOM generation follows the pattern used in the .NET workflow on master:
Benefits
Files Modified
.github/workflows/publish.chefsupermaket.yml
- Complete workflow improvementsintegration/keeper_secrets_manager_chef/cookbooks/keeper_secrets_manager/metadata.rb
- Fixed URLsTesting
All critical workflow logic has been validated through three-layer testing approach:
Ready for workflow execution testing on this branch.
Next Steps
After workflow testing is complete, these changes will be integrated into PR #771 for final merge.