Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 190 additions & 128 deletions .github/workflows/README.md

Large diffs are not rendered by default.

229 changes: 229 additions & 0 deletions .github/workflows/docker_apply_cache.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
name: "03 Maintain: Apply Package Cache"
description: "Generate the package cache for the lesson after a pull request has been merged or via manual trigger, and cache in S3 or GitHub"
on:
workflow_dispatch:
inputs:
name:
description: 'Who triggered this build?'
required: true
default: 'Maintainer (via GitHub)'
pull_request:
types:
- closed
branches:
- main

# queue cache runs
concurrency:
group: docker-apply-cache
cancel-in-progress: false

jobs:
preflight:
name: "Preflight: PR or Manual Trigger?"
runs-on: ubuntu-latest
outputs:
do-apply: ${{ steps.check.outputs.merged_or_manual }}
steps:
- name: "Should we run cache application?"
id: check
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ||
("${{ github.ref }}" == "refs/heads/main" && "${{ github.event.action }}" == "closed" && "${{ github.event.pull_request.merged }}" == "true") ]]; then
echo "merged_or_manual=true" >> $GITHUB_OUTPUT
else
echo "This was not a manual trigger and no PR was merged. No action taken."
echo "merged_or_manual=false" >> $GITHUB_OUTPUT
fi
shell: bash

check-renv:
Comment on lines +23 to +40

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}

Copilot Autofix

AI about 1 month ago

To fix the issue, add an explicit permissions block to the preflight job (the one starting at line 22). Since this job only runs a shell script and does not interact with repository contents, PRs, or other resources via the GitHub API, it can safely be restricted to contents: read (or even contents: none; however, contents: read is a very common minimal default and matches the query’s recommended pattern). This explicitly documents and constrains the GITHUB_TOKEN permissions for that job while leaving the behavior of the workflow unchanged.

Concretely:

  • In .github/workflows/docker_apply_cache.yaml, within the preflight job definition (lines 22–38), insert a permissions: section under runs-on: ubuntu-latest, setting contents: read.
  • No additional imports, methods, or definitions are needed; this is a pure YAML configuration change.
Suggested changeset 1
.github/workflows/docker_apply_cache.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/docker_apply_cache.yaml b/.github/workflows/docker_apply_cache.yaml
--- a/.github/workflows/docker_apply_cache.yaml
+++ b/.github/workflows/docker_apply_cache.yaml
@@ -22,6 +22,8 @@
   preflight:
     name: "Preflight: PR or Manual Trigger?"
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     outputs:
       do-apply: ${{ steps.check.outputs.merged_or_manual }}
     steps:
EOF
@@ -22,6 +22,8 @@
preflight:
name: "Preflight: PR or Manual Trigger?"
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
do-apply: ${{ steps.check.outputs.merged_or_manual }}
steps:
Copilot is powered by AI and may make mistakes. Always verify output.
name: "Check If We Need {renv}"
runs-on: ubuntu-latest
needs: preflight
if: needs.preflight.outputs.do-apply == 'true'
permissions:
id-token: write
outputs:
renv-needed: ${{ steps.check-for-renv.outputs.renv-needed }}
renv-cache-hashsum: ${{ steps.check-for-renv.outputs.renv-cache-hashsum }}
renv-cache-available: ${{ steps.check-for-renv.outputs.renv-cache-available }}
steps:
- name: "Check for renv"
id: check-for-renv
uses: carpentries/actions/renv-checks@main
with:
role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }}
aws-region: ${{ secrets.AWS_GH_OIDC_REGION }}
WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG || 'latest' }}
token: ${{ secrets.GITHUB_TOKEN }}

no-renv-cache-used:
name: "No renv cache used"
runs-on: ubuntu-latest
needs: check-renv
if: needs.check-renv.outputs.renv-needed != 'true'
steps:
- name: "No renv cache needed"
run: echo "No renv cache needed for this lesson"

renv-cache-available:
Comment on lines +62 to +70

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}

Copilot Autofix

AI about 1 month ago

In general, the fix is to explicitly set a permissions block to restrict GITHUB_TOKEN to the least privilege needed. This can be done either at the workflow root (applies to all jobs that don’t override it) or per job. Since one job (check-renv) already has its own permissions block, the cleanest approach is to set a minimal read-only default at the workflow level and leave check-renv’s specific id-token: write override as-is.

Concretely:

  • Add a root-level permissions: block near the top of .github/workflows/docker_apply_cache.yaml (e.g., after the on: section and before concurrency:) that sets contents: read. This is a safe, minimal default that will apply to jobs such as preflight, no-renv-cache-used, renv-cache-available, update-renv-cache, and record-cache-result, none of which need write access to repository contents.
  • Keep the existing permissions block for check-renv unchanged so it can still obtain an OIDC id-token for AWS role assumption.
  • No additional imports, methods, or definitions are needed since this is a GitHub Actions YAML configuration change only.
Suggested changeset 1
.github/workflows/docker_apply_cache.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/docker_apply_cache.yaml b/.github/workflows/docker_apply_cache.yaml
--- a/.github/workflows/docker_apply_cache.yaml
+++ b/.github/workflows/docker_apply_cache.yaml
@@ -13,6 +13,9 @@
     branches:
       - main
 
+permissions:
+  contents: read
+
 # queue cache runs
 concurrency:
   group: docker-apply-cache
EOF
@@ -13,6 +13,9 @@
branches:
- main

permissions:
contents: read

# queue cache runs
concurrency:
group: docker-apply-cache
Copilot is powered by AI and may make mistakes. Always verify output.
name: "renv cache available"
runs-on: ubuntu-latest
needs: check-renv
if: needs.check-renv.outputs.renv-cache-available == 'true'
steps:
- name: "renv cache available"
run: echo "renv cache available for this lesson"

update-renv-cache:
Comment on lines +71 to +79

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}

Copilot Autofix

AI about 1 month ago

In general, fix this by explicitly specifying permissions: for the workflow (and overriding per job if a job needs more than the minimal set). For jobs that only need to read repository contents and metadata, contents: read is sufficient; jobs that upload artifacts to the Actions storage do not need extra repo permissions beyond this. Only jobs that interact with issues, PRs, packages, etc. should request write scopes for those specific resources.

For this specific workflow, the simplest and least intrusive fix is to add a root-level permissions block that applies to all jobs, specifying a minimal, read-only configuration. From the visible code, the jobs shown (check-renv, no-renv-cache-used, renv-cache-available, update-renv-cache, record-cache-result) either call other actions, echo text, or upload an artifact. None of these require write access to repository contents. Therefore, adding at the top level:

permissions:
  contents: read

will constrain GITHUB_TOKEN appropriately without breaking existing behavior. We do not need to add job-specific permissions for renv-cache-available or record-cache-result; they will inherit the root permissions. The change should be inserted after the on: block (for clarity) and before concurrency: or jobs:. No new imports, methods, or other definitions are needed, since this is a YAML configuration change only.

Suggested changeset 1
.github/workflows/docker_apply_cache.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/docker_apply_cache.yaml b/.github/workflows/docker_apply_cache.yaml
--- a/.github/workflows/docker_apply_cache.yaml
+++ b/.github/workflows/docker_apply_cache.yaml
@@ -13,6 +13,9 @@
     branches:
       - main
 
+permissions:
+  contents: read
+
 # queue cache runs
 concurrency:
   group: docker-apply-cache
EOF
@@ -13,6 +13,9 @@
branches:
- main

permissions:
contents: read

# queue cache runs
concurrency:
group: docker-apply-cache
Copilot is powered by AI and may make mistakes. Always verify output.
name: "Update renv Cache"
runs-on: ubuntu-latest
needs: check-renv
if: |
needs.check-renv.outputs.renv-needed == 'true' &&
needs.check-renv.outputs.renv-cache-available != 'true' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.event.pull_request.merged == true &&
(
(
contains(
join(github.event.pull_request.labels.*.name, ','),
'type: package cache'
) &&
github.event.pull_request.head.ref == 'update/packages'
)
||
(
contains(
join(github.event.pull_request.labels.*.name, ','),
'type: workflows'
) &&
github.event.pull_request.head.ref == 'update/workflows'
)
||
(
contains(
join(github.event.pull_request.labels.*.name, ','),
'type: docker version'
) &&
github.event.pull_request.head.ref == 'update/workbench-docker-version'
)
)
)
)
permissions:
checks: write
contents: write
pages: write
id-token: write
container:
image: ghcr.io/carpentries/workbench-docker:${{ vars.WORKBENCH_TAG || 'latest' }}
env:
WORKBENCH_PROFILE: "ci"
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
RENV_PATHS_ROOT: /home/rstudio/lesson/renv
RENV_PROFILE: "lesson-requirements"
RENV_VERSION: ${{ needs.check-renv.outputs.renv-cache-hashsum }}
RENV_CONFIG_EXTERNAL_LIBRARIES: "/usr/local/lib/R/site-library"
volumes:
- ${{ github.workspace }}:/home/rstudio/lesson
options: --cpus 2
steps:
- uses: actions/checkout@v4

- name: "Debugging Info"
run: |
echo "Current Directory: $(pwd)"
ls -lah /home/rstudio/.workbench
ls -lah $(pwd)
Rscript -e 'sessionInfo()'
shell: bash

- name: "Mark Repository as Safe"
run: |
git config --global --add safe.directory $(pwd)
shell: bash

- name: "Ensure sandpaper is loadable"
run: |
.libPaths()
library(sandpaper)
shell: Rscript {0}

- name: "Setup Lesson Dependencies"
run: |
Rscript /home/rstudio/.workbench/setup_lesson_deps.R
shell: bash

- name: "Fortify renv Cache"
run: |
Rscript /home/rstudio/.workbench/fortify_renv_cache.R
shell: bash

- name: "Get Container Version Used"
id: wb-vers
uses: carpentries/actions/container-version@main
with:
WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG }}
renv-needed: ${{ needs.check-renv.outputs.renv-needed }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: "Validate Current Org and Workflow"
id: validate-org-workflow
uses: carpentries/actions/validate-org-workflow@main
with:
repo: ${{ github.repository }}
workflow: ${{ github.workflow }}

- name: "Configure AWS credentials via OIDC"
id: aws-creds
env:
role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }}
aws-region: ${{ secrets.AWS_GH_OIDC_REGION }}
if: |
steps.validate-org-workflow.outputs.is_valid == 'true' &&
env.role-to-assume != '' &&
env.aws-region != ''
uses: aws-actions/configure-aws-credentials@v5.0.0
with:
role-to-assume: ${{ env.role-to-assume }}
aws-region: ${{ env.aws-region }}
output-credentials: true

- name: "Upload cache object to S3"
id: upload-cache
uses: carpentries/actions-cache@frog-matchedkey-1
with:
accessKey: ${{ steps.aws-creds.outputs.aws-access-key-id }}
secretKey: ${{ steps.aws-creds.outputs.aws-secret-access-key }}
sessionToken: ${{ steps.aws-creds.outputs.aws-session-token }}
bucket: workbench-docker-caches
path: |
/home/rstudio/lesson/renv
/usr/local/lib/R/site-library
key: ${{ github.repository }}/${{ steps.wb-vers.outputs.container-version }}_renv-${{ needs.check-renv.outputs.renv-cache-hashsum }}
restore-keys:
${{ github.repository }}/${{ steps.wb-vers.outputs.container-version }}_renv-

record-cache-result:
name: "Record Caching Status"
runs-on: ubuntu-latest
needs: [check-renv, update-renv-cache]
if: always()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: "Record cache result"

run: |
echo "${{ needs.update-renv-cache.result == 'success' || needs.check-renv.outputs.renv-cache-available == 'true' || 'false' }}" > ${{ github.workspace }}/apply-cache-result
shell: bash

- name: "Upload cache result"
uses: actions/upload-artifact@v4
with:
name: apply-cache-result
path: ${{ github.workspace }}/apply-cache-result
Comment on lines +212 to +229

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}

Copilot Autofix

AI about 1 month ago

In general, the fix is to explicitly declare a permissions block in the workflow (at the top level or per-job) that grants only the minimal scopes required. If none of the jobs need to modify repository contents, issues, or pull requests, you can set contents: read at the workflow level. This both documents the intended access and prevents the workflow from accidentally inheriting broader write permissions from the repository or organization defaults.

For this specific workflow file .github/workflows/docker_apply_cache.yaml, the simplest and safest fix without changing functionality is to add a top-level permissions block right after the on: section. The jobs shown (including record-cache-result) only read workflow context, configure AWS credentials via OIDC, and upload an artifact. None of these operations require write access to repository contents, issues, or pull requests. Therefore, setting permissions: contents: read at the workflow root is appropriate and will apply to all jobs, including record-cache-result, unless any job overrides it. No additional imports or methods are required as this is purely a YAML configuration change.

Concretely:

  • Edit .github/workflows/docker_apply_cache.yaml.
  • After the on: block (after line 14), insert:
permissions:
  contents: read
  • Keep indentation consistent with the existing top-level keys (name, description, on, concurrency, jobs).
  • No other regions or files need to be altered.
Suggested changeset 1
.github/workflows/docker_apply_cache.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/docker_apply_cache.yaml b/.github/workflows/docker_apply_cache.yaml
--- a/.github/workflows/docker_apply_cache.yaml
+++ b/.github/workflows/docker_apply_cache.yaml
@@ -13,6 +13,9 @@
     branches:
       - main
 
+permissions:
+  contents: read
+
 # queue cache runs
 concurrency:
   group: docker-apply-cache
EOF
@@ -13,6 +13,9 @@
branches:
- main

permissions:
contents: read

# queue cache runs
concurrency:
group: docker-apply-cache
Copilot is powered by AI and may make mistakes. Always verify output.
161 changes: 161 additions & 0 deletions .github/workflows/docker_build_deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: "01 Maintain: Build and Deploy Site"
description: "Build and deploy the lesson site using the carpentries/workbench-docker container"
on:
push:
branches:
- 'main'
- 'l10n_main'
paths-ignore:
- '.github/workflows/**.yaml'
- '.github/workbench-docker-version.txt'
schedule:
- cron: '0 0 * * 2'
workflow_run:
workflows: ["03 Maintain: Apply Package Cache"]
types:
- completed
workflow_dispatch:
inputs:
name:
description: 'Who triggered this build?'
required: true
default: 'Maintainer (via GitHub)'
CACHE_VERSION:
description: 'Optional renv cache version override'
required: false
default: ''
reset:
description: 'Reset cached markdown files'
required: true
default: false
type: boolean
force-skip-manage-deps:
description: 'Skip build-time dependency management'
required: true
default: false
type: boolean

# only one build/deploy at a time
concurrency:
group: docker-build-deploy
cancel-in-progress: true

jobs:
preflight:
name: "Preflight: Schedule, Push, or PR?"
runs-on: ubuntu-latest
outputs:
do-build: ${{ steps.build-check.outputs.do-build }}
renv-needed: ${{ steps.build-check.outputs.renv-needed }}
renv-cache-hashsum: ${{ steps.build-check.outputs.renv-cache-hashsum }}
workbench-container-file-exists: ${{ steps.wb-vers.outputs.workbench-container-file-exists }}
wb-vers: ${{ steps.wb-vers.outputs.container-version }}
last-wb-vers: ${{ steps.wb-vers.outputs.last-container-version }}
workbench-update: ${{ steps.wb-vers.outputs.workbench-update }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: "Should we run build and deploy?"
id: build-check
uses: carpentries/actions/build-preflight@main

- name: "Checkout Lesson"
if: steps.build-check.outputs.do-build == 'true'
uses: actions/checkout@v4

- name: "Get container version info"
id: wb-vers
if: steps.build-check.outputs.do-build == 'true'
uses: carpentries/actions/container-version@main
with:
WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG }}
renv-needed: ${{ steps.build-check.outputs.renv-needed }}
token: ${{ secrets.GITHUB_TOKEN }}

full-build:
Comment on lines +45 to +75

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 5 days ago

To fix the problem, explicitly declare restricted permissions for the preflight job so it does not inherit broad repository defaults. Since preflight only runs checks and calls actions that read repository metadata, contents: read is sufficient and aligns with the CodeQL recommendation.

The best minimally invasive fix is:

  • Add a permissions block under jobs.preflight with only contents: read.
  • Leave the existing permissions blocks for full-build and update-container-version unchanged.
  • Do not alter any steps, environment variables, or other job configuration.

Concretely, in .github/workflows/docker_build_deploy.yaml, edit the preflight job definition (around lines 44–57). Insert:

    permissions:
      contents: read

between runs-on: ubuntu-latest and outputs:. No imports or additional definitions are required, as this is pure workflow YAML.

Suggested changeset 1
.github/workflows/docker_build_deploy.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/docker_build_deploy.yaml b/.github/workflows/docker_build_deploy.yaml
--- a/.github/workflows/docker_build_deploy.yaml
+++ b/.github/workflows/docker_build_deploy.yaml
@@ -44,6 +44,8 @@
   preflight:
     name: "Preflight: Schedule, Push, or PR?"
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     outputs:
       do-build: ${{ steps.build-check.outputs.do-build }}
       renv-needed: ${{ steps.build-check.outputs.renv-needed }}
EOF
@@ -44,6 +44,8 @@
preflight:
name: "Preflight: Schedule, Push, or PR?"
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
do-build: ${{ steps.build-check.outputs.do-build }}
renv-needed: ${{ steps.build-check.outputs.renv-needed }}
Copilot is powered by AI and may make mistakes. Always verify output.
name: "Build Full Site"
runs-on: ubuntu-latest
needs: preflight
if: |
needs.preflight.outputs.do-build == 'true' &&
needs.preflight.outputs.workbench-update != 'true'
env:
RENV_EXISTS: ${{ needs.preflight.outputs.renv-needed }}
RENV_HASH: ${{ needs.preflight.outputs.renv-cache-hashsum }}
permissions:
checks: write
contents: write
pages: write
id-token: write
container:
image: ghcr.io/carpentries/workbench-docker:${{ vars.WORKBENCH_TAG || 'latest' }}
env:
WORKBENCH_PROFILE: "ci"
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
RENV_PATHS_ROOT: /home/rstudio/lesson/renv
RENV_PROFILE: "lesson-requirements"
RENV_CONFIG_EXTERNAL_LIBRARIES: "/usr/local/lib/R/site-library"
volumes:
- ${{ github.workspace }}:/home/rstudio/lesson
options: --cpus 1
steps:
- uses: actions/checkout@v4

- name: "Debugging Info"
run: |
cd /home/rstudio/lesson
echo "Current Directory: $(pwd)"
echo "RENV_HASH is $RENV_HASH"
ls -lah /home/rstudio/.workbench
ls -lah $(pwd)
Rscript -e 'sessionInfo()'
shell: bash

- name: "Mark Repository as Safe"
run: |
git config --global --add safe.directory $(pwd)
shell: bash

- name: "Setup Lesson Dependencies"
id: build-container-deps
uses: carpentries/actions/build-container-deps@main
with:
CACHE_VERSION: ${{ vars.CACHE_VERSION || github.event.inputs.CACHE_VERSION || '' }}
WORKBENCH_TAG: ${{ vars.WORKBENCH_TAG || 'latest' }}
LESSON_PATH: ${{ vars.LESSON_PATH || '/home/rstudio/lesson' }}
role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }}
aws-region: ${{ secrets.AWS_GH_OIDC_REGION }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: "Run Container and Build Site"
id: build-and-deploy
uses: carpentries/actions/build-and-deploy@main
with:
reset: ${{ vars.BUILD_RESET || github.event.inputs.reset || 'false' }}
skip-manage-deps: ${{ github.event.inputs.force-skip-manage-deps == 'true' || steps.build-container-deps.outputs.renv-cache-available || steps.build-container-deps.outputs.backup-cache-used || 'false' }}
lang-code: ${{ vars.LANG_CODE || '' }}

update-container-version:
name: "Update container version used"
runs-on: ubuntu-latest
needs: [preflight]
permissions:
actions: write
contents: write
pull-requests: write
id-token: write
if: |
needs.preflight.outputs.do-build == 'true' &&
(
needs.preflight.outputs.workbench-container-file-exists == 'false' ||
needs.preflight.outputs.workbench-update == 'true'
)
steps:
- name: "Record container version used"
uses: carpentries/actions/record-container-version@main
with:
CONTAINER_VER: ${{ needs.preflight.outputs.wb-vers }}
AUTO_MERGE: ${{ vars.AUTO_MERGE_CONTAINER_VERSION_UPDATE || 'true' }}
token: ${{ secrets.GITHUB_TOKEN }}
role-to-assume: ${{ secrets.AWS_GH_OIDC_ARN }}
aws-region: ${{ secrets.AWS_GH_OIDC_REGION }}
Loading
Loading