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

The best fix is to add a workflow-level permissions block near the top of .github/workflows/docker_apply_cache.yaml, so all jobs get a restricted default token scope. Keep existing job-level overrides (like check-renv with id-token: write) unchanged, because job-level permissions can extend/override as needed for OIDC.

For this workflow, a safe minimal baseline is:

  • contents: read (common read access for repository content)
  • optionally actions: read if needed by marketplace actions resolution (often not required explicitly, but acceptable)

Given the static analysis recommendation and least-privilege principle, adding permissions: { contents: read } at workflow root is the single best low-risk change that does not alter intended functionality.

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
@@ -1,5 +1,7 @@
 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"
+permissions:
+  contents: read
 on:
   workflow_dispatch:
     inputs:
EOF
@@ -1,5 +1,7 @@
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"
permissions:
contents: read
on:
workflow_dispatch:
inputs:
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

Add an explicit root-level permissions block for the workflow so all jobs (including no-renv-cache-used) are constrained by default. Use least privilege baseline:

  • contents: read (common minimal read access),
  • packages: read (recommended minimal for package-related workflows; harmless if unused).

Keep the existing check-renv job-level permissions block (id-token: write) as-is, since it appears to require OIDC for AWS role assumption. Job-level permissions will override/augment defaults for that job as needed.

Where to change: .github/workflows/docker_apply_cache.yaml, near the top-level keys (after concurrency is a clean location), before jobs:.

No imports/dependencies/methods are needed (YAML config 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
@@ -18,6 +18,10 @@
   group: docker-apply-cache
   cancel-in-progress: false
 
+permissions:
+  contents: read
+  packages: read
+
 jobs:
   preflight:
     name: "Preflight: PR or Manual Trigger?"
EOF
@@ -18,6 +18,10 @@
group: docker-apply-cache
cancel-in-progress: false

permissions:
contents: read
packages: read

jobs:
preflight:
name: "Preflight: PR or Manual Trigger?"
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

Add an explicit root-level permissions block in .github/workflows/docker_apply_cache.yaml so all jobs without their own permissions inherit least-privilege defaults. The safest minimal baseline here is:

  • contents: read (common for checkout/read repo metadata)
  • packages: read (often needed for package/container pulls)

Keep existing job-specific permissions (like the one already under update-renv-cache) unchanged; job-level permissions will continue to override root-level defaults where needed.
Edit near the top of the workflow (after concurrency is a clean location) and add the block before jobs:.

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
@@ -18,6 +18,10 @@
   group: docker-apply-cache
   cancel-in-progress: false
 
+permissions:
+  contents: read
+  packages: read
+
 jobs:
   preflight:
     name: "Preflight: PR or Manual Trigger?"
EOF
@@ -18,6 +18,10 @@
group: docker-apply-cache
cancel-in-progress: false

permissions:
contents: read
packages: read

jobs:
preflight:
name: "Preflight: PR or Manual Trigger?"
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@v6

- 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@v6
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: tespkg/actions-cache@v1.10.0
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@v7
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

Add an explicit permissions block to the workflow so all jobs (including record-cache-result) inherit least-privilege defaults.
Best single fix with minimal functional change: add a root-level permissions section after concurrency and before jobs.

Given this workflow uploads artifacts and uses OIDC for AWS credentials, include:

  • contents: read (safe baseline for checkout/read operations),
  • actions: read (safe for reading action metadata),
  • id-token: write (required for OIDC token minting used by aws-actions/configure-aws-credentials).

No imports/dependencies/methods are needed (YAML config only).
File to edit: .github/workflows/docker_apply_cache.yaml in the top-level section around lines 16–21.

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
@@ -18,6 +18,11 @@
   group: docker-apply-cache
   cancel-in-progress: false
 
+permissions:
+  contents: read
+  actions: read
+  id-token: write
+
 jobs:
   preflight:
     name: "Preflight: PR or Manual Trigger?"
EOF
@@ -18,6 +18,11 @@
group: docker-apply-cache
cancel-in-progress: false

permissions:
contents: read
actions: read
id-token: write

jobs:
preflight:
name: "Preflight: PR or Manual Trigger?"
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@v6

- 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 about 1 month ago

Add an explicit permissions block to the preflight job in .github/workflows/docker_build_deploy.yaml so the token is minimally scoped for that job.
Best single fix (without changing functionality): set contents: read under jobs.preflight, since the job checks out code and reads metadata, and there is no shown write operation in that job. Keep existing permissions for other jobs unchanged.

Edit region: in .github/workflows/docker_build_deploy.yaml, directly under:

  • preflight:
  • name: "Preflight: Schedule, Push, or PR?"
  • runs-on: ubuntu-latest

insert:

permissions:
  contents: read

No imports/dependencies/methods are needed.

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@v6

- 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