Skip to content

Commit 02f8311

Browse files
Merge branch 'main' into docs/add-repository-name-limits
2 parents b72d0a2 + 0aa6981 commit 02f8311

126 files changed

Lines changed: 7152 additions & 1734 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/instructions/content.instructions.md

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,23 @@ Examples:
9595

9696
## Versioning
9797

98-
Avoid `{% ifversion fpt %}`, `{% ifversion ghec %}`, and `{% ifversion fpt or ghec %}` in content files whenever possible. Instead of suggesting or adding version-gating within an article:
98+
Follow one of these sets of instructions, depending on how articles are versioned in the frontmatter. Articles may be versioned for FPT and GHEC, for GHES only, or for all three. Articles may also be versioned using feature-based versioning defined in `data/features`. Feature-based versioning allows centralized control of when content appears for specific GHES releases.
9999

100-
* Write content that applies to all versions the article is versioned for
101-
* If content is truly version-specific, consider whether it is low-harm to show it to all readers (e.g., an enterprise-only row in a reference table)
102-
* Only use `{% ifversion %}` as a last resort when content would be actively misleading for readers on a different version
100+
### FPT/GHEC-only articles
103101

104-
**FPT and GHEC content**: When dotcom content applies to both products, version the page for `fpt` and `ghec` in the frontmatter. Do NOT use in-article Liquid versioning. Do NOT suggest adding `{% ifversion fpt or ghec %}` blocks as a fix for content that mentions a dotcom-only feature. Instead, suggest rewriting the content using the alternatives to inline versioning options listed below.
102+
All articles that are ONLY for FPT and GHEC should be versioned for these versions in the frontmatter.
105103

106-
**GHES content**: If versioning is necessary for GitHub Enterprise Server content, use feature-based versioning (FBV). GHES content should rely on feature flags defined in `data/features/` rather than inline `{% ifversion ghes %}` blocks. Feature flags allow centralized control of when content appears for specific GHES releases.
104+
For such content, DO NOT use in-article Liquid versioning such as `{% ifversion fpt %}`, `{% ifversion ghec %}`, and `{% ifversion fpt or ghec %}`.
107105

108-
### Alternatives to inline versioning
106+
### GHES-only articles
107+
108+
All articles that are ONLY for GitHub Enterprise Server (GHES) should be versioned in the frontmatter using feature-based versioning defined in `data/features/`.
109+
110+
### FPT, GHEC, GHES articles
111+
112+
All articles that are versioned for all of FPT, GHEC, and GHES in the frontmatter MAY require certain blocks of content to be versioned using in-article Liquid versioning. Before recommending this, check if this is really the case.
113+
114+
#### Check in-article versioning is required
109115

110116
Before resorting to in-article versioning, first consider whether the content is actually different across versions. Often procedures can be simplified to work at both levels.
111117

@@ -127,26 +133,6 @@ Use these strategies instead of `{% ifversion %}`, depending on the level of con
127133
* End list items with "({% data variables.product.prodname_ghe_cloud %} only)", "({% data variables.product.prodname_dotcom_the_website %} only)", etc.
128134
* Specify if the feature is not available for GHES with "NAME-OF-FEATURE is not available for {% data variables.product.prodname_ghe_server %}", "... (not available in {% data variables.product.prodname_ghe_server %})", etc.
129135

130-
### Example
131-
132-
When documenting a feature that only applies to dotcom (not GHES):
133-
134-
❌ Don't wrap content in version blocks:
135-
136-
```markdown
137-
{% ifversion fpt or ghec %}
138-
139-
## Immutable subject claims
140-
141-
Repositories created after July 15, 2026 now use an immutable default subject format.
142-
143-
{% endif %}
144-
```
145-
146-
✅ Do use prose to indicate availability:
147-
148-
```markdown
149-
## Immutable subject claims
136+
#### If in-article versioning is required
150137

151-
Repositories created after July 15, 2026 now use an immutable default subject format. This rollout does not include {% data variables.product.prodname_ghe_server %}.
152-
```
138+
In-article versioning is required if a block of content in an article is definitely ONLY relevant for GHES, but the article itself is otherwise versioned in the frontmatter for all of FPT, GHEC, and GHES. In this situation, use feature-based versioning (FBV) wherever possible, using `{% ifversion FBV %}` blocks, where FBV is defined in `data/features/`. If it's not possible to use FBV, use {% ifversion ghes %} blocks, which will version the content block for all versions of GHES.

.github/workflows/index-general-search.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,7 @@ jobs:
231231
env:
232232
FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }}
233233
FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }}
234-
FASTLY_SURROGATE_KEY: api-search:${{ matrix.language }}
235-
run: npm run purge-fastly-edge-cache
234+
run: npm run purge-fastly -- --surrogate-key api-search:${{ matrix.language }}
236235

237236
- name: Upload failures artifact
238237
if: ${{ steps.check-failures.outputs.has_failures == 'true' }}

.github/workflows/purge-fastly-all.yml

Lines changed: 0 additions & 44 deletions
This file was deleted.

.github/workflows/purge-fastly.yml

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,50 @@
11
name: Purge Fastly
22

3-
# **What it does**: Sends a soft-purge to Fastly.
4-
# **Why we have it**: So that, right after a production deploy, we start afresh
5-
# **Who does it impact**: Writers and engineers.
3+
# **What it does**: Purges Fastly after a deploy and on demand. Soft purge by
4+
# default; can hard purge specific languages, or hard purge the ENTIRE cache.
5+
# **Why we have it**: So that, right after a production deploy, we start afresh,
6+
# and so docs engineering can clear a bad cache state without the Fastly UI.
7+
# **Who does it impact**: Writers and engineers. A full purge impacts all readers,
8+
# origin sees a traffic spike while the cache refills, so it's gated below.
69

710
on:
811
deployment_status:
912
workflow_dispatch:
1013
inputs:
1114
languages:
12-
description: "Comma separated languages. E.g. 'en,es,ja,pt,zh,ru,fr,ko,de' (defaults to en)"
15+
description: "Languages: Comma separated languages, e.g. 'en,es,ja,pt,zh,ru,fr,ko,de'. Blank = all languages."
1316
required: false
14-
default: 'en' # Temporary, only purge English on deploy. Set to empty string for all
17+
default: 'en'
18+
hard:
19+
description: 'Hard purge: Evict immediately instead of the default soft purge. Use when a soft purge fails to clear stale content.'
20+
type: boolean
21+
required: false
22+
default: false
23+
everything:
24+
description: 'Everything: Hard-purge the entire Fastly cache... every key, all readers. Ignores the languages/hard inputs. To confirm, type exactly: "purge everything". Otherwise leave blank.'
25+
required: false
26+
default: ''
1527

1628
permissions:
1729
contents: read
1830

31+
# Serialize full-cache purges so two can't overlap and leave the cache in an
32+
# unknown state. Every other run (per-deploy, per-language) gets a unique group
33+
# so those never block each other.
34+
concurrency:
35+
group: ${{ (inputs.everything == 'purge everything' && 'purge-fastly-all') || format('purge-fastly-{0}', github.run_id) }}
36+
cancel-in-progress: false
37+
1938
env:
2039
FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }}
2140
FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }}
2241

2342
jobs:
2443
send-purges:
25-
# Run when workflow_dispatch is the event (manual) or when deployment_status is the event (automatic) and it's a successful production deploy.
26-
# NOTE: This workflow triggers on all deployment_status events (including staging), but only runs for production.
44+
# Run when workflow_dispatch is the event
45+
# or when deployment_status is the event and it's a successful production deploy.
46+
# NOTE: This workflow triggers on all deployment_status events,
47+
# including staging, but only runs for production.
2748
# Non-production deploys will show as "skipped" - this is expected behavior.
2849
if: >-
2950
${{
@@ -38,52 +59,50 @@ jobs:
3859

3960
- uses: ./.github/actions/node-npm-setup
4061

41-
- name: Wait for production to match build commit SHA
42-
if: github.event_name != 'workflow_dispatch'
43-
# A single /_build match only proves *one* Moda instance is serving the
44-
# new build; others can still be mid-rollout. If we purge then, Fastly's
45-
# soft purge serves stale-while-revalidate and may revalidate against a
46-
# lagging instance, re-caching old content as fresh for a full TTL. So we
47-
# require several consecutive matches to confirm the rollout has settled
48-
# across instances before purging.
62+
- name: Validate confirmation input
63+
# A full-cache purge only triggers on the exact string "purge everything".
64+
# Any other non-empty value (e.g. a typo) would otherwise be silently
65+
# ignored and fall through to a normal soft purge that finishes green, so
66+
# an operator could think they evicted the whole cache when they didn't.
67+
# Fail loudly instead.
68+
env:
69+
EVERYTHING_INPUT: ${{ inputs.everything }}
4970
run: |
50-
needs=$(git rev-parse HEAD)
51-
start_time=$(date +%s)
52-
timeout_seconds=1200
53-
required_matches=5
54-
interval_seconds=10
55-
consecutive=0
56-
while [[ $consecutive -lt $required_matches ]]
57-
do
58-
if [[ $(($(date +%s) - $start_time)) -gt $timeout_seconds ]]
59-
then
60-
echo "Production did not reach $required_matches consecutive build matches within $timeout_seconds seconds"
61-
exit 1
62-
fi
63-
if [[ $needs == $(curl -s --fail --retry-connrefused --retry 5 https://docs.github.com/_build) ]]
64-
then
65-
consecutive=$((consecutive + 1))
66-
echo "Production matches the build commit ($consecutive/$required_matches)"
67-
else
68-
if [[ $consecutive -gt 0 ]]
69-
then
70-
echo "Production stopped matching the build commit; resetting consecutive count"
71-
else
72-
echo "Production is not up to date with the build commit"
73-
fi
74-
consecutive=0
75-
fi
76-
if [[ $consecutive -lt $required_matches ]]
77-
then
78-
sleep $interval_seconds
79-
fi
80-
done
81-
echo "Production is up to date with the build commit ($required_matches consecutive matches)"
71+
if [ -n "$EVERYTHING_INPUT" ] && [ "$EVERYTHING_INPUT" != "purge everything" ]; then
72+
echo "::error::To purge the entire cache, the 'everything' input must be exactly 'purge everything'. Got: '$EVERYTHING_INPUT'. Leave it blank for a normal purge."
73+
exit 1
74+
fi
8275
83-
- name: Purge Fastly edge cache per language
76+
- name: Purge Fastly
77+
# Auto post-deploy runs wait for the build, purge English only (temporary),
78+
# and stay soft. A manual run uses the inputs: blank languages = all, the
79+
# `hard` toggle, or a confirmed full-cache purge.
80+
#
81+
# Raw inputs are passed through the environment and quoted, never spliced
82+
# into the command string, so a value like `en' --everything` can't break
83+
# out of its argument and inject another flag.
8484
env:
85-
LANGUAGES: ${{ inputs.languages || 'en' }} # Temporary, only purge English on deploy. Set to empty string for all
86-
run: npm run purge-fastly-edge-cache-per-language
85+
EVENT_NAME: ${{ github.event_name }}
86+
LANGUAGES_INPUT: ${{ inputs.languages }}
87+
HARD_INPUT: ${{ inputs.hard }}
88+
EVERYTHING_INPUT: ${{ inputs.everything }}
89+
run: |
90+
args=()
91+
if [ "$EVENT_NAME" != "workflow_dispatch" ]; then
92+
args+=(--wait-for-build)
93+
fi
94+
if [ "$EVENT_NAME" = "deployment_status" ]; then
95+
args+=(--languages en)
96+
elif [ -n "$LANGUAGES_INPUT" ]; then
97+
args+=(--languages "$LANGUAGES_INPUT")
98+
fi
99+
if [ "$HARD_INPUT" = "true" ]; then
100+
args+=(--hard)
101+
fi
102+
if [ "$EVERYTHING_INPUT" = "purge everything" ]; then
103+
args+=(--everything)
104+
fi
105+
npm run purge-fastly -- "${args[@]}"
87106
88107
- uses: ./.github/actions/slack-alert
89108
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
19.4 KB
Loading

content/actions/how-tos/manage-runners/larger-runners/use-custom-images.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ To create a custom image, you must first set up an image-generation runner. When
4444
* **Platform**: Select a supported platform that matches the platform of the image you plan to create (Linux x64, Linux ARM64, or Windows x64).
4545
* **Image**: Select an image to build on, then enable the checkbox **Enable this runner to generate custom images**.
4646
* You can start from a {% data variables.product.github %}-owned image or choose a base image to start from a clean OS.
47+
* You can start from an existing custom image as the base, enabling layered image workflows.
4748
* For ARM64 platforms, you can also select an ARM-maintained image with preinstalled tooling.
4849
* **Runner group**: Select the group for your runner to be a member of. Once the custom image is created, only runners in this runner group can generate new versions of that image.
4950

@@ -139,6 +140,12 @@ If you specify an older major version in the YAML (for example, version: 1.* whe
139140
> [!NOTE]
140141
> {% data variables.actions.github_hosted_larger_runner %} creation does not support wildcards in image version selection.
141142
143+
## Expiration for images built from custom images
144+
145+
When a custom image is built from another custom image, the derived image inherits the expiration timeline of its base image. The maximum version age is calculated from when the base custom image was built, not when the derived image was created.
146+
147+
For example, if Custom Image A is built on Day 2 and Custom Image B is built from A on Day 4 with a 7-day maximum version age policy, both A and B expire on Day 9.
148+
142149
## Billing and storage for custom images
143150

144151
Jobs that use custom images are billed at the same per-minute rate as the {% data variables.actions.hosted_runner %} that uses the image. Storage for custom images is billed separately through {% data variables.product.prodname_actions %} storage.

content/actions/reference/security/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ versions:
88
ghec: '*'
99
children:
1010
- /secure-use
11+
- /securely-using-pull_request_target
1112
- /secrets
1213
- /oidc
1314
contentType: reference

content/actions/reference/security/secure-use.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,6 @@ For more information, see [AUTOTITLE](/code-security/code-scanning/introduction-
106106

107107
To help mitigate the risk of an exposed token, consider restricting the assigned permissions. For more information, see [AUTOTITLE](/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token).
108108

109-
{% ifversion custom-org-roles %}
110-
111109
## Mitigating the risks of untrusted code checkout
112110

113111
Similar to script injection attacks, untrusted pull request content that automatically triggers actions processing can also pose a security risk. The `pull_request_target` and `workflow_run` workflow triggers, when used with the checkout of an untrusted pull request, expose the repository to security compromises. These workflows are privileged, which means they share the same cache of the main branch with other privileged workflow triggers, and may have repository write access and access to referenced secrets. These vulnerabilities can be exploited to take over a repository.
@@ -116,6 +114,8 @@ For more information on these triggers, how to use them, and the associated risk
116114

117115
For additional examples and guidance on the risks of untrusted code checkout, see [Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) from {% data variables.product.prodname_security %} and the [Dangerous-Workflow](https://github.com/ossf/scorecard/blob/main/docs/checks.md#dangerous-workflow) documentation from OpenSSF Scorecard.
118116

117+
For detailed guidance on deciding whether to use `pull_request_target`, hardening these workflows, and opting out of the `actions/checkout` protection, see [AUTOTITLE](/actions/reference/security/securely-using-pull_request_target).
118+
119119
### Good practices
120120

121121
* Avoid using the `pull_request_target` workflow trigger if it's not necessary. For privilege separation between workflows, `workflow_run` is a better trigger. Only use these workflow triggers when the workflow actually needs the privileged context.
@@ -126,8 +126,6 @@ For additional examples and guidance on the risks of untrusted code checkout, se
126126

127127
* OpenSSF Scorecards can help you identify potentially vulnerable workflows, along with other security risks when using {% data variables.product.prodname_actions %}. See [Using OpenSSF Scorecards to secure workflow dependencies](#using-openssf-scorecards-to-secure-workflow-dependencies) later in this article.
128128

129-
{% endif %}
130-
131129
## Using third-party actions
132130

133131
The individual jobs in a workflow can interact with (and compromise) other jobs. For example, a job querying the environment variables used by a later job, writing files to a shared directory that a later job processes, or even more directly by interacting with the Docker socket and inspecting other running containers and executing commands in them.

0 commit comments

Comments
 (0)