diff --git a/.github/workflows/build-targets.yaml b/.github/workflows/build-targets.yaml index 91ceb13..93341ca 100644 --- a/.github/workflows/build-targets.yaml +++ b/.github/workflows/build-targets.yaml @@ -1,9 +1,6 @@ name: Build Code Editor Targets on: - push: - branches: - - 'main' - - '*.*' + workflow_dispatch: jobs: build: diff --git a/.github/workflows/security-scan.yaml b/.github/workflows/security-scan.yaml index cdbf7d4..47a6987 100644 --- a/.github/workflows/security-scan.yaml +++ b/.github/workflows/security-scan.yaml @@ -1,16 +1,11 @@ name: Security Scan -env: - CODE_EDITOR_TARGETS: '["code-editor-sagemaker-server"]' - on: - # Trigger 1: PR created on main or version branches (*.*) - # Temporarily disabled until security review is complete. - # pull_request_target: - # branches: - # - main - # - '*.*' - # types: [opened, reopened, synchronize] + # Trigger 1: Merge to main or version branches (*.*) + push: + branches: + - main + - '*.*' # Trigger 2: Daily scheduled run at 00:13 UTC # Schedule it a random minute because most Github Actions are scheduled @@ -21,6 +16,16 @@ on: # Trigger 3: Manual trigger workflow_dispatch: + inputs: + standalone-run: + description: 'Run as standalone workflow (skip build workflow invocation)' + required: false + type: boolean + default: false + +env: + CODE_EDITOR_TARGETS: '["code-editor-sagemaker-server"]' + STANDALONE_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.standalone-run || false }} jobs: get-branches-to-scan: @@ -35,31 +40,30 @@ jobs: with: fetch-depth: 0 - - name: Determine branches for PR events + - name: Determine branches for merge events id: determine-pr-branches - if: github.event_name == 'pull_request_target' + if: github.event_name == 'push' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - # For PR events, validate base branch and use head ref if valid - echo "Base branch: $GITHUB_BASE_REF" - echo "Head branch: $GITHUB_HEAD_REF" + # For merge events, use the branch that was merged to + echo "Merged to branch: $GITHUB_REF_NAME" - if [[ "$GITHUB_BASE_REF" =~ ^[0-9]+\.[0-9]+$ ]] || [[ "$GITHUB_BASE_REF" == "main" ]]; then - echo "Base branch matches allowed pattern (main or digit.digit)" - echo "branches=[\"$GITHUB_HEAD_REF\"]" >> "$GITHUB_OUTPUT" - echo "output-branch-name=$GITHUB_BASE_REF" >> "$GITHUB_OUTPUT" - echo "Branches to scan: [$GITHUB_HEAD_REF]" - echo "Output files will use branch name: $GITHUB_BASE_REF" + if [[ "$GITHUB_REF_NAME" =~ ^[0-9]+\.[0-9]+$ ]] || [[ "$GITHUB_REF_NAME" == "main" ]]; then + echo "Branch matches allowed pattern (main or digit.digit)" + echo "branches=[\"$GITHUB_REF_NAME\"]" >> "$GITHUB_OUTPUT" + echo "output-branch-name=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT" + echo "Branches to scan: [$GITHUB_REF_NAME]" + echo "Output files will use branch name: $GITHUB_REF_NAME" else - echo "Base branch does not match allowed pattern - no branches to scan" + echo "Branch does not match allowed pattern - no branches to scan" echo "branches=[]" >> "$GITHUB_OUTPUT" echo "output-branch-name=" >> "$GITHUB_OUTPUT" fi - name: Get all upstream branches id: get-upstream-branches - if: github.event_name != 'pull_request_target' + if: github.event_name != 'push' run: | # Get main branch and all version branches (*.*) branches=$(git branch -r | grep -E 'origin/(main|[0-9]+\.[0-9]+)$' | sed 's/origin\///' | tr '\n' ' ') @@ -69,7 +73,7 @@ jobs: - name: Get completed workflows from previous day id: get-completed-workflows - if: github.event_name != 'pull_request_target' + if: github.event_name != 'push' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -93,7 +97,7 @@ jobs: - name: Check for successful scan artifacts from previous day id: check-scan-artifacts - if: github.event_name != 'pull_request_target' + if: github.event_name != 'push' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPOSITORY: ${{ github.repository }} @@ -144,7 +148,7 @@ jobs: - name: Determine security scan branches for scheduled runs id: determine-scheduled-security-scan-branches - if: github.event_name != 'pull_request_target' + if: github.event_name != 'push' run: | upstream_branches="${{ steps.get-upstream-branches.outputs.upstream-branches }}" successful_branches="${{ steps.check-scan-artifacts.outputs.successful-security-scan-branches }}" @@ -181,7 +185,7 @@ jobs: - name: Determine global dependencies branches for scheduled runs id: determine-scheduled-global-dependencies-branches - if: github.event_name != 'pull_request_target' + if: github.event_name != 'push' run: | upstream_branches="${{ steps.get-upstream-branches.outputs.upstream-branches }}" successful_branches="${{ steps.check-scan-artifacts.outputs.successful-global-dependencies-branches }}" @@ -252,19 +256,36 @@ jobs: - name: Checkout branch uses: actions/checkout@v4 with: - # For fork-origin PRs, we can't directly use matrix.branch as the branch does not exist in the - # Code Editor repo. The branch only exists in the fork. - ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || matrix.branch }} + ref: ${{ matrix.branch }} submodules: recursive - - name: Update security scan script from main + - name: Update scripts from main branch + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPOSITORY: ${{ github.repository }} run: | # Older branches may not have the latest versions of the - # security scan scripts. So we download the latest one from main - echo "Downloading latest security-scan.sh script from main branch" - curl -sSL "https://raw.githubusercontent.com/${{ github.repository }}/main/scripts/security-scan.sh" -o scripts/security-scan.sh - sudo chmod +x scripts/security-scan.sh - echo "Updated security-scan.sh to latest version from main" + # security scan scripts. So we download the latest scripts folder from main + echo "Downloading latest scripts folder from main branch" + + cd scripts + rm -f *.sh + + gh api "/repos/$REPOSITORY/contents/scripts?ref=main" --jq '.[] | select(.type == "file" and (.name | endswith(".sh"))) | .name' | \ + while read filename; do + echo "Downloading: $filename" + raw_url="https://raw.githubusercontent.com/$REPOSITORY/main/scripts/$filename" + curl -sSL "$raw_url" -o "$filename" + if [ -s "$filename" ]; then + echo "✓ Successfully downloaded: $filename ($(wc -c < "$filename") bytes)" + else + echo "✗ Failed to download: $filename" + exit 1 + fi + done + sudo chmod +x *.sh + + echo "Updated scripts folder to latest version from main" - name: Set up environment run: | @@ -296,7 +317,6 @@ jobs: echo "Installing CycloneDX SBOM for npm" npm i -g @cyclonedx/cyclonedx-npm - - name: Run Security Scan env: TARGET: ${{ matrix.target }} @@ -336,24 +356,17 @@ jobs: - name: Create Success Indicator File env: - EVENT_NAME: ${{ github.event_name }} - OUTPUT_BRANCH_NAME: ${{ needs.get-branches-to-scan.outputs.output-branch-name }} MATRIX_BRANCH: ${{ matrix.branch }} TARGET: ${{ matrix.target }} run: | - # For PR events, use base_ref as output branch name, otherwise use actual branch - if [ "$EVENT_NAME" = "pull_request_target" ]; then - output_branch="$OUTPUT_BRANCH_NAME" - else - output_branch="$MATRIX_BRANCH" - fi + output_branch="$MATRIX_BRANCH" echo "PASS" > "scan-success-$TARGET-${output_branch}.txt" - name: Upload Success Indicator File uses: actions/upload-artifact@v4 with: - name: scan-success-${{ matrix.target }}-${{ github.event_name == 'pull_request_target' && needs.get-branches-to-scan.outputs.output-branch-name || matrix.branch }} - path: scan-success-${{ matrix.target }}-${{ github.event_name == 'pull_request_target' && needs.get-branches-to-scan.outputs.output-branch-name || matrix.branch }}.txt + name: scan-success-${{ matrix.target }}-${{ matrix.branch }} + path: scan-success-${{ matrix.target }}-${{ matrix.branch }}.txt retention-days: 90 - name: Publish Scan Successful Metric @@ -369,7 +382,7 @@ jobs: --value 1 - name: Publish Failure Metrics - if: failure() && github.event_name == 'schedule' + if: failure() && github.event_name != 'workflow_dispatch' env: REPOSITORY: ${{ github.repository }} TARGET: ${{ matrix.target }} @@ -401,19 +414,11 @@ jobs: - name: Check if branch was successful for all targets env: - EVENT_NAME: ${{ github.event_name }} - OUTPUT_BRANCH_NAME: ${{ needs.get-branches-to-scan.outputs.output-branch-name }} MATRIX_BRANCH: ${{ matrix.branch }} run: | # Parse targets from environment variable readarray -t targets < <(jq -r '.[]' <<< "$CODE_EDITOR_TARGETS") - - # For PR events, use base_ref as output branch name, otherwise use actual branch - if [ "$EVENT_NAME" = "pull_request_target" ]; then - check_branch="$OUTPUT_BRANCH_NAME" - else - check_branch="$MATRIX_BRANCH" - fi + check_branch="$MATRIX_BRANCH" all_success=true @@ -447,8 +452,8 @@ jobs: if: success() uses: actions/upload-artifact@v4 with: - name: scan-success-branch-${{ github.event_name == 'pull_request_target' && needs.get-branches-to-scan.outputs.output-branch-name || matrix.branch }} - path: scan-success-branch-${{ github.event_name == 'pull_request_target' && needs.get-branches-to-scan.outputs.output-branch-name || matrix.branch }}.txt + name: scan-success-branch-${{ matrix.branch }} + path: scan-success-branch-${{ matrix.branch }}.txt retention-days: 90 security-scan-global-dependencies: @@ -485,20 +490,35 @@ jobs: - name: Checkout branch uses: actions/checkout@v4 with: - # For fork-origin PRs, we can't directly use matrix.branch as the branch does not exist in the - # Code Editor repo. The branch only exists in the fork. - ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || matrix.branch }} + ref: ${{ matrix.branch }} submodules: recursive - - name: Update security scan script from main + - name: Update scripts from main branch env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPOSITORY: ${{ github.repository }} run: | # Older branches may not have the latest versions of the # security scan scripts. So we download the latest one from main echo "Downloading latest security-scan.sh script from main branch" - curl -sSL "https://raw.githubusercontent.com/$REPOSITORY/main/scripts/security-scan.sh" -o scripts/security-scan.sh - sudo chmod +x scripts/security-scan.sh + + cd scripts + rm -f *.sh + + gh api "/repos/$REPOSITORY/contents/scripts?ref=main" --jq '.[] | select(.type == "file" and (.name | endswith(".sh"))) | .name' | \ + while read filename; do + echo "Downloading: $filename" + raw_url="https://raw.githubusercontent.com/$REPOSITORY/main/scripts/$filename" + curl -sSL "$raw_url" -o "$filename" + if [ -s "$filename" ]; then + echo "✓ Successfully downloaded: $filename ($(wc -c < "$filename") bytes)" + else + echo "✗ Failed to download: $filename" + exit 1 + fi + done + sudo chmod +x *.sh + echo "Updated security-scan.sh to latest version from main" - name: Install Security Scan Dependencies @@ -550,27 +570,20 @@ jobs: - name: Create Global Success Indicator File env: - EVENT_NAME: ${{ github.event_name }} - OUTPUT_BRANCH_NAME: ${{ needs.get-branches-to-scan.outputs.output-branch-name }} MATRIX_BRANCH: ${{ matrix.branch }} run: | - # For PR events, use base_ref as output branch name, otherwise use actual branch - if [ "$EVENT_NAME" = "pull_request_target" ]; then - output_branch="$OUTPUT_BRANCH_NAME" - else - output_branch="$MATRIX_BRANCH" - fi + output_branch="$MATRIX_BRANCH" echo "PASS" > "global-scan-success-${output_branch}.txt" - name: Upload Global Success Indicator File uses: actions/upload-artifact@v4 with: - name: global-scan-success-${{ github.event_name == 'pull_request_target' && needs.get-branches-to-scan.outputs.output-branch-name || matrix.branch }} - path: global-scan-success-${{ github.event_name == 'pull_request_target' && needs.get-branches-to-scan.outputs.output-branch-name || matrix.branch }}.txt + name: global-scan-success-${{ matrix.branch }} + path: global-scan-success-${{ matrix.branch }}.txt retention-days: 90 - name: Publish Failure Metrics - if: failure() && github.event_name == 'schedule' + if: failure() && github.event_name != 'workflow_dispatch' env: REPOSITORY: ${{ github.repository }} BRANCH: ${{ matrix.branch }} @@ -584,12 +597,32 @@ jobs: --dimensions "Repository=$REPOSITORY,Workflow=GlobalDependenciesSecurityScan,Branch=$BRANCH" \ --value 1 + invoke-build-workflow: + name: Invoke Build Workflow + runs-on: ubuntu-latest + needs: [generate-security-scan-output, security-scan-global-dependencies] + if: success() && (github.event_name != 'workflow_dispatch' || !inputs.standalone-run) + permissions: + actions: write # Required for workflow invocation + contents: read + steps: + - name: Trigger Build Workflow + uses: actions/github-script@v8 + with: + script: | + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: "build-targets.yaml", + ref: context.ref + }) + handle-failures: name: Handle Failures runs-on: ubuntu-latest - needs: [get-branches-to-scan, generate-security-scan-output] + needs: [generate-security-scan-output] environment: security-scanning-workflow-env - if: failure() && github.event_name == 'schedule' + if: failure() && github.event_name != 'workflow_dispatch' permissions: id-token: write # Required for OIDC env: @@ -608,4 +641,4 @@ jobs: --namespace "GitHub/Workflows" \ --metric-name "ExecutionsFailed" \ --dimensions "Repository=$REPOSITORY,Workflow=SecurityScan" \ - --value 1 + --value 1 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 02df6d4..c823224 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,9 +21,9 @@ reported the issue. Please try to include as much information as you can. Detail ## Ensure security before each commit -Configure git-secrets and run it before every commit. Make sure that secrets are not committed to Git version control. +1. Configure git-secrets and run it before every commit. Make sure that secrets are not committed to Git version control. Follow [this guide](https://github.com/awslabs/git-secrets) before making a commit and push to your branch. - +1. All variable interpolation should be considered unsafe by default. Extract all GitHub expressions to an environment variable before using them in inline scripts for GitHub Actions. Refer GitHub's guide [here](https://docs.github.com/en/enterprise-cloud@latest/actions/reference/security/secure-use#use-an-intermediate-environment-variable) for more information. ## Contributing via Pull Requests Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: