1
0
mirror of synced 2025-12-19 18:10:59 -05:00

Merge pull request #39019 from github/repo-sync

Repo sync
This commit is contained in:
docs-bot
2025-06-23 14:32:41 -07:00
committed by GitHub
25 changed files with 137 additions and 107 deletions

View File

@@ -20,7 +20,7 @@ jobs:
# need to use a token from a user with access to github/github for this step # need to use a token from a user with access to github/github for this step
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
REPORT_AUTHOR: docs-bot REPORT_AUTHOR: docs-bot
REPORT_LABEL: github github broken link report REPORT_LABEL: github github broken link report,workflow-generated
REPORT_REPOSITORY: github/docs-content REPORT_REPOSITORY: github/docs-content
steps: steps:
- name: Checkout - name: Checkout

View File

@@ -45,7 +45,7 @@ jobs:
- name: Create an issue in the docs-content repo - name: Create an issue in the docs-content repo
run: | run: |
new_issue_url="$(gh issue create --title "$ISSUE_TITLE" --body "$ISSUE_BODY" --repo github/docs-content)" new_issue_url="$(gh issue create --title "$ISSUE_TITLE" --body "$ISSUE_BODY" --repo github/docs-content --label "workflow-generated")"
echo 'NEW_ISSUE='$new_issue_url >> $GITHUB_ENV echo 'NEW_ISSUE='$new_issue_url >> $GITHUB_ENV
env: env:
GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}} GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}}

View File

@@ -130,6 +130,7 @@ jobs:
--body '👋 humans. This PR was generated from docs-internal/.github/workflows/delete-orphan-translation-files.yml. --body '👋 humans. This PR was generated from docs-internal/.github/workflows/delete-orphan-translation-files.yml.
' \ ' \
--repo "${{ matrix.language_repo }}" \ --repo "${{ matrix.language_repo }}" \
--label "workflow-generated" \
--head=$branch_name --head=$branch_name
echo "Merge created PR..." echo "Merge created PR..."
retry_command gh pr merge --merge --auto --delete-branch "$branch_name" retry_command gh pr merge --merge --auto --delete-branch "$branch_name"

View File

@@ -152,7 +152,7 @@ jobs:
gh pr create \ gh pr create \
--title "Update CodeQL query tables" \ --title "Update CodeQL query tables" \
--repo github/docs-internal \ --repo github/docs-internal \
--label "codeql-query-tables,skip FR board,ready-for-doc-review" \ --label "codeql-query-tables,skip FR board,ready-for-doc-review,workflow-generated" \
--body '👋 humans. This PR updates the **CodeQL query table reusables** with the latest changes in preparation for the next **CodeQL CLI** release. --body '👋 humans. This PR updates the **CodeQL query table reusables** with the latest changes in preparation for the next **CodeQL CLI** release.
No action is required from the first responder for the Docs content team. This PR will be reviewed and merged by the Code scanning and GHAS focus team as part of the next release of CodeQL CLI. (Synced from codeql@${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }}) No action is required from the first responder for the Docs content team. This PR will be reviewed and merged by the Code scanning and GHAS focus team as part of the next release of CodeQL CLI. (Synced from codeql@${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }})

View File

@@ -49,6 +49,7 @@ jobs:
gh pr create \ gh pr create \
--title "Update list of allowed IPs" \ --title "Update list of allowed IPs" \
--body 'This PR updates the list of allowed IPs in Moda. It is automatically generated.' \ --body 'This PR updates the list of allowed IPs in Moda. It is automatically generated.' \
--label "workflow-generated" \
--head=$branchname --head=$branchname
echo "Pull request created" echo "Pull request created"

View File

@@ -97,7 +97,7 @@ jobs:
--title "Delete orphaned features ($date)" \ --title "Delete orphaned features ($date)" \
--body "$body" \ --body "$body" \
--repo github/docs-internal \ --repo github/docs-internal \
--label docs-content-fr --label docs-content-fr,workflow-generated
- uses: ./.github/actions/slack-alert - uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name == 'schedule' }} if: ${{ failure() && github.event_name == 'schedule' }}

View File

@@ -105,7 +105,7 @@ jobs:
--title "Delete orphaned files ($date)" \ --title "Delete orphaned files ($date)" \
--body "$body" \ --body "$body" \
--repo github/docs-internal \ --repo github/docs-internal \
--label docs-content-fr --label docs-content-fr,workflow-generated
- uses: ./.github/actions/slack-alert - uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name == 'schedule' }} if: ${{ failure() && github.event_name == 'schedule' }}

View File

@@ -54,5 +54,5 @@ jobs:
- Reviewer stating they'll need to get back to us at a later time - Reviewer stating they'll need to get back to us at a later time
- Review provided was unclear or missing key information, and a follow-up is necessary - Review provided was unclear or missing key information, and a follow-up is necessary
`, `,
labels: ['on track','open source', 'sme-review'], labels: ['on track','open source', 'sme-review', 'workflow-generated'],
}); });

View File

@@ -91,7 +91,7 @@ jobs:
Make sure the PR builds successfully and there are no gross errors (for example, a file is deleted). You do not need to validate the contents (that is the responsibility of product teams). Make sure the PR builds successfully and there are no gross errors (for example, a file is deleted). You do not need to validate the contents (that is the responsibility of product teams).
If CI does not pass or other problems arise, contact #docs-engineering on slack.' \ If CI does not pass or other problems arise, contact #docs-engineering on slack.' \
--repo github/docs-internal \ --repo github/docs-internal \
--label audit-log-pipeline \ --label audit-log-pipeline,workflow-generated \
--head=$branchname --head=$branchname
echo "Created pull request" echo "Created pull request"

View File

@@ -108,7 +108,7 @@ jobs:
If CI does not pass or other problems arise, contact #docs-engineering on slack.' \ If CI does not pass or other problems arise, contact #docs-engineering on slack.' \
--repo github/docs-internal \ --repo github/docs-internal \
--label "codeql-cli-pipeline,skip FR board,ready-for-doc-review" --label "codeql-cli-pipeline,skip FR board,ready-for-doc-review,workflow-generated"
- uses: ./.github/actions/slack-alert - uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }} if: ${{ failure() && github.event_name != 'workflow_dispatch' }}

View File

@@ -114,7 +114,7 @@ jobs:
If CI does not pass or other problems arise, contact #docs-engineering on slack.' \ If CI does not pass or other problems arise, contact #docs-engineering on slack.' \
--repo github/docs-internal \ --repo github/docs-internal \
--label github-openapi-bot \ --label github-openapi-bot,workflow-generated \
--head=$branchname \ --head=$branchname \
- uses: ./.github/actions/slack-alert - uses: ./.github/actions/slack-alert

View File

@@ -76,7 +76,7 @@ jobs:
If CI does not pass or other problems arise, contact #docs-engineering on Slack.' \ If CI does not pass or other problems arise, contact #docs-engineering on Slack.' \
--repo github/docs-internal \ --repo github/docs-internal \
--label secret-scanning-pipeline,'skip FR board',ready-for-doc-review \ --label secret-scanning-pipeline,'skip FR board',ready-for-doc-review,workflow-generated \
--head=$branchname --head=$branchname
- uses: ./.github/actions/slack-alert - uses: ./.github/actions/slack-alert

View File

@@ -4,6 +4,7 @@ labels:
- enterprise deprecation - enterprise deprecation
- priority-1 - priority-1
- time sensitive - time sensitive
- workflow-generated
--- ---
# Deprecation steps for GHES releases # Deprecation steps for GHES releases

View File

@@ -8,7 +8,7 @@ labels:
- skip FR board - skip FR board
- GHES {{ release-number }} - GHES {{ release-number }}
- ghes-release-automation - ghes-release-automation
- rhythm of docs operations - workflow-generated
--- ---
This issue tracks Docs work for the GA release of GHES {{ release-number }}. This issue tracks Docs work for the GA release of GHES {{ release-number }}.

View File

@@ -7,6 +7,7 @@ labels:
- skip FR board - skip FR board
- rhythm of docs operations - rhythm of docs operations
- GHES {{ release-number }} - GHES {{ release-number }}
- workflow-generated
--- ---
## Instructions for triage ## Instructions for triage

View File

@@ -7,6 +7,7 @@ labels:
- skip FR board - skip FR board
- GHES {{ release-number }} - GHES {{ release-number }}
- rhythm of docs operations - rhythm of docs operations
- workflow-generated
--- ---
## Instructions for triage ## Instructions for triage

View File

@@ -5,6 +5,7 @@ labels:
- new-release - new-release
- priority-0 - priority-0
- GHES {{ release-number }} - GHES {{ release-number }}
- workflow-generated
--- ---
Docs Content will publish docs for the GHES {{ release-number }} RC soon. Please draft a release note for the latest supported version of the CodeQL CLI, and update the docs to reflect the latest supported version. Docs Content will publish docs for the GHES {{ release-number }} RC soon. Please draft a release note for the latest supported version of the CodeQL CLI, and update the docs to reflect the latest supported version.

View File

@@ -4,6 +4,7 @@ labels:
- Enterprise - Enterprise
- priority-0 - priority-0
- skip FR board - skip FR board
- workflow-generated
--- ---
Docs Content will publish docs for the GHES {{ release-number }} RC soon. Please update the docs to reflect the minimum required version of the Actions Runner application for the new release. Docs Content will publish docs for the GHES {{ release-number }} RC soon. Please update the docs to reflect the minimum required version of the Actions Runner application for the new release.

View File

@@ -7,6 +7,7 @@ labels:
- priority-0 - priority-0
- skip FR board - skip FR board
- rhythm of docs operations - rhythm of docs operations
- workflow-generated
--- ---
## Instructions for triage ## Instructions for triage

View File

@@ -1,7 +1,7 @@
import type { NextFunction, Response } from 'express' import type { NextFunction, Response } from 'express'
import { formatReleases, renderPatchNotes } from '@/release-notes/lib/release-notes-utils' import { formatReleases, renderPatchNotes } from '@/release-notes/lib/release-notes-utils'
import { all } from '@/versions/lib/enterprise-server-releases.js' import { all, latestStable } from '@/versions/lib/enterprise-server-releases.js'
import { executeWithFallback } from '@/languages/lib/render-with-fallback.js' import { executeWithFallback } from '@/languages/lib/render-with-fallback.js'
import { getReleaseNotes } from './get-release-notes' import { getReleaseNotes } from './get-release-notes'
import type { Context, ExtendedRequest } from '@/types' import type { Context, ExtendedRequest } from '@/types'
@@ -87,7 +87,7 @@ export default async function ghesReleaseNotesContext(
// GHES release notes on docs started with 2.20 but older release notes exist on enterprise.github.com. // GHES release notes on docs started with 2.20 but older release notes exist on enterprise.github.com.
// So we want to use _all_ GHES versions when calculating next and previous releases. // So we want to use _all_ GHES versions when calculating next and previous releases.
req.context.latestPatch = req.context.ghesReleaseNotes![0].version req.context.latestPatch = req.context.ghesReleaseNotes![0].version
req.context.latestRelease = all[0] req.context.latestRelease = latestStable
// Add convenience props for "Supported releases" section on GHES Admin landing page (NOT release notes). // Add convenience props for "Supported releases" section on GHES Admin landing page (NOT release notes).
req.context.ghesReleases.forEach((release) => { req.context.ghesReleases.forEach((release) => {

View File

@@ -6,6 +6,8 @@ import { beforeAll, describe, expect, test } from 'vitest'
import yaml from 'js-yaml' import yaml from 'js-yaml'
import { liquid } from '@/content-render/index.js' import { liquid } from '@/content-render/index.js'
import { getDataByLanguage } from '@/data-directory/lib/get-data.js'
import { allVersions } from '@/versions/lib/all-versions.js'
interface ReleaseNoteContent { interface ReleaseNoteContent {
intro: string intro: string
@@ -34,7 +36,7 @@ describe('lint enterprise release notes', () => {
yamlContent = yaml.load(fileContents) as ReleaseNoteContent yamlContent = yaml.load(fileContents) as ReleaseNoteContent
}) })
test('contains valid liquid', () => { test('contains valid liquid', async () => {
const { intro, sections } = yamlContent const { intro, sections } = yamlContent
let toLint: Record<string, string> = { intro } let toLint: Record<string, string> = { intro }
for (const key in sections) { for (const key in sections) {
@@ -54,9 +56,28 @@ describe('lint enterprise release notes', () => {
}) })
} }
// Create context with site data for rendering liquid variables
const context = {
currentLanguage: 'en',
currentVersionObj: allVersions['free-pro-team@latest'],
site: {
data: {
reusables: getDataByLanguage('reusables', 'en'),
variables: getDataByLanguage('variables', 'en'),
ui: getDataByLanguage('ui', 'en'),
},
},
}
for (const key in toLint) { for (const key in toLint) {
if (!toLint[key]) continue if (!toLint[key]) continue
// First check if liquid parses correctly
expect(() => liquid.parse(toLint[key]), `${key} contains invalid liquid`).not.toThrow() expect(() => liquid.parse(toLint[key]), `${key} contains invalid liquid`).not.toThrow()
// Then check if liquid renders correctly with context
await expect(
liquid.parseAndRender(toLint[key], context),
`${key} contains liquid that fails to render`,
).resolves.not.toThrow()
} }
}) })

View File

@@ -381,54 +381,6 @@ export function AskAIResults({
return ( return (
<div id="ask-ai-result-container" role="region" className={styles.container}> <div id="ask-ai-result-container" role="region" className={styles.container}>
{!aiCouldNotAnswer && references && references.length > 0 ? (
<>
<ActionList className={styles.referencesList} showDividers>
<ActionList.Group>
<ActionList.GroupHeading
as="h3"
aria-label={t('search.ai.references')}
className={styles.referencesTitle}
>
{t('search.ai.references')}
</ActionList.GroupHeading>
{references
.map((source, index) => {
if (index >= MAX_REFERENCES_TO_SHOW) {
return null
}
const refIndex = index + referencesIndexOffset
return (
<ActionList.Item
sx={{
marginLeft: '0px',
}}
key={`reference-${index}`}
id={`search-option-reference-${index + referencesIndexOffset}`}
tabIndex={-1}
onSelect={() => {
referenceOnSelect(source.url)
}}
active={refIndex === selectedIndex}
ref={(element) => {
if (listElementsRef.current) {
listElementsRef.current[refIndex] = element
}
}}
>
<ActionList.LeadingVisual aria-hidden="true">
<FileIcon />
</ActionList.LeadingVisual>
{source.title}
</ActionList.Item>
)
})
.filter(Boolean)}
</ActionList.Group>
<ActionList.Divider aria-hidden="true" />
</ActionList>
</>
) : null}
<ActionList.GroupHeading <ActionList.GroupHeading
key="ai-heading" key="ai-heading"
as="h3" as="h3"
@@ -529,6 +481,54 @@ export function AskAIResults({
></IconButton> ></IconButton>
</div> </div>
) : null} ) : null}
{!aiCouldNotAnswer && references && references.length > 0 ? (
<>
<ActionList.Divider aria-hidden="true" />
<ActionList className={styles.referencesList} showDividers>
<ActionList.Group>
<ActionList.GroupHeading
as="h3"
aria-label={t('search.ai.references')}
className={styles.referencesTitle}
>
{t('search.ai.references')}
</ActionList.GroupHeading>
{references
.map((source, index) => {
if (index >= MAX_REFERENCES_TO_SHOW) {
return null
}
const refIndex = index + referencesIndexOffset
return (
<ActionList.Item
sx={{
marginLeft: '0px',
}}
key={`reference-${index}`}
id={`search-option-reference-${index + referencesIndexOffset}`}
tabIndex={-1}
onSelect={() => {
referenceOnSelect(source.url)
}}
active={refIndex === selectedIndex}
ref={(element) => {
if (listElementsRef.current) {
listElementsRef.current[refIndex] = element
}
}}
>
<ActionList.LeadingVisual aria-hidden="true">
<FileIcon />
</ActionList.LeadingVisual>
{source.title}
</ActionList.Item>
)
})
.filter(Boolean)}
</ActionList.Group>
</ActionList>
</>
) : null}
<div <div
aria-live="assertive" aria-live="assertive"
style={{ style={{

View File

@@ -266,12 +266,12 @@ export function SearchOverlay({
// Fetch initial search results on open // Fetch initial search results on open
useEffect(() => { useEffect(() => {
if (searchOverlayOpen && (!isAskAIState || aiSearchError || aiCouldNotAnswer)) { if (searchOverlayOpen) {
if (!searchEventGroupId.current) { if (!searchEventGroupId.current) {
searchEventGroupId.current = uuidv4() searchEventGroupId.current = uuidv4()
} }
updateAutocompleteResults(urlSearchInputQuery) updateAutocompleteResults(urlSearchInputQuery)
} else if (isAskAIState || aiSearchError || aiCouldNotAnswer) { } else {
// When opening the overlay via query params, we don't need to fetch autocomplete results // When opening the overlay via query params, we don't need to fetch autocomplete results
// However, on initial open, we need to clear the loading state // However, on initial open, we need to clear the loading state
setSearchLoading(false) setSearchLoading(false)
@@ -628,7 +628,10 @@ export function SearchOverlay({
/> />
</Box> </Box>
</li> </li>
<ActionList.Divider key="error-bottom-divider" /> {/* If there are general results, show bottom divider */}
{generalOptionsWithViewStatus.length > 0 && (
<ActionList.Divider key="error-middle-divider" />
)}
</> </>
)} )}
{renderSearchGroups( {renderSearchGroups(
@@ -885,36 +888,8 @@ function renderSearchGroups(
const groups = [] const groups = []
let isInAskAIState = askAIState?.isAskAIState && !askAIState.aiSearchError let isInAskAIState = askAIState?.isAskAIState && !askAIState.aiSearchError
if (isInAskAIState) {
groups.push(
<ActionList.Group key="ai" data-testid="ask-ai">
<li tabIndex={-1}>
<AskAIResults
query={askAIState.aiQuery}
debug={askAIState.debug}
version={askAIState.currentVersion}
setAISearchError={askAIState.setAISearchError}
references={askAIState.references}
setReferences={askAIState.setReferences}
referencesIndexOffset={askAIState.referencesIndexOffset}
referenceOnSelect={askAIState.referenceOnSelect}
selectedIndex={selectedIndex}
askAIEventGroupId={askAIState.askAIEventGroupId}
aiCouldNotAnswer={askAIState.aiCouldNotAnswer}
setAICouldNotAnswer={askAIState.setAICouldNotAnswer}
listElementsRef={listElementsRef}
/>
</li>
</ActionList.Group>,
)
}
let isInAskAIStateButNoAnswer = isInAskAIState && askAIState.aiCouldNotAnswer let isInAskAIStateButNoAnswer = isInAskAIState && askAIState.aiCouldNotAnswer
if (isInAskAIStateButNoAnswer) {
groups.push(<ActionList.Divider key="no-answer-divider" />)
}
// already showing spinner when streaming AI response, so don't want to show 2 here // already showing spinner when streaming AI response, so don't want to show 2 here
if (showSpinner && !isInAskAIState) { if (showSpinner && !isInAskAIState) {
groups.push( groups.push(
@@ -932,8 +907,8 @@ function renderSearchGroups(
return groups return groups
} }
// We want to show general search suggestions underneath the AI Response section if the AI Could no answer // We want to show general search suggestions above the AI Response section if the AI could not answer
if ((generalSearchOptions.length && !isInAskAIState) || isInAskAIStateButNoAnswer) { if (generalSearchOptions.length || isInAskAIStateButNoAnswer) {
const items = [] const items = []
for (let index = 0; index < generalSearchOptions.length; index++) { for (let index = 0; index < generalSearchOptions.length; index++) {
const option = generalSearchOptions[index] const option = generalSearchOptions[index]
@@ -1034,17 +1009,43 @@ function renderSearchGroups(
</ActionList.Group>, </ActionList.Group>,
) )
if (isInAskAIState || isInAskAIStateButNoAnswer) {
groups.push(<ActionList.Divider key="no-answer-divider" />)
}
if (isInAskAIState) {
groups.push(
<ActionList.Group key="ai" data-testid="ask-ai">
<li tabIndex={-1}>
<AskAIResults
query={askAIState.aiQuery}
debug={askAIState.debug}
version={askAIState.currentVersion}
setAISearchError={askAIState.setAISearchError}
references={askAIState.references}
setReferences={askAIState.setReferences}
referencesIndexOffset={askAIState.referencesIndexOffset}
referenceOnSelect={askAIState.referenceOnSelect}
selectedIndex={selectedIndex}
askAIEventGroupId={askAIState.askAIEventGroupId}
aiCouldNotAnswer={askAIState.aiCouldNotAnswer}
setAICouldNotAnswer={askAIState.setAICouldNotAnswer}
listElementsRef={listElementsRef}
/>
</li>
</ActionList.Group>,
)
}
// Don't show the bottom divider if: // Don't show the bottom divider if:
// 1. We are in the AI could not answer state // 1. We are in the AI could not answer state
// 2. We are in the AI Search error state // 2. We are in the AI Search error state
// 3. There are no AI suggestions to show in suggestions state // 3. There are no AI suggestions to show in suggestions state
if ( if (
!askAIState.aiCouldNotAnswer && !isInAskAIState &&
!askAIState.aiSearchError && !askAIState.aiSearchError &&
(!askAIState.isAskAIState || generalSearchOptions.filter((option) => !option.isViewAllResults && !option.isNoResultsFound)
generalSearchOptions.filter( .length &&
(option) => !option.isViewAllResults && !option.isNoResultsFound,
).length) &&
aiOptionsWithUserInput.length aiOptionsWithUserInput.length
) { ) {
groups.push(<ActionList.Divider key="bottom-divider" />) groups.push(<ActionList.Divider key="bottom-divider" />)

View File

@@ -1351,7 +1351,7 @@
isPublic: true isPublic: true
isPrivateWithGhas: true isPrivateWithGhas: true
hasPushProtection: false hasPushProtection: false
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}' hasValidityCheck: false
isduplicate: false isduplicate: false
- provider: Dropbox - provider: Dropbox
supportedSecret: Dropbox Short-Lived Access Token supportedSecret: Dropbox Short-Lived Access Token
@@ -3531,7 +3531,7 @@
isPublic: false isPublic: false
isPrivateWithGhas: true isPrivateWithGhas: true
hasPushProtection: true hasPushProtection: true
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}' hasValidityCheck: false
isduplicate: false isduplicate: false
- provider: Shippo - provider: Shippo
supportedSecret: Shippo Test API Token supportedSecret: Shippo Test API Token
@@ -3543,7 +3543,7 @@
isPublic: false isPublic: false
isPrivateWithGhas: true isPrivateWithGhas: true
hasPushProtection: false hasPushProtection: false
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}' hasValidityCheck: false
isduplicate: false isduplicate: false
- provider: Shopee - provider: Shopee
supportedSecret: Shopee Open Platform Partner Key supportedSecret: Shopee Open Platform Partner Key
@@ -3698,7 +3698,7 @@
isPublic: true isPublic: true
isPrivateWithGhas: true isPrivateWithGhas: true
hasPushProtection: false hasPushProtection: false
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}' hasValidityCheck: false
isduplicate: true isduplicate: true
- provider: Slack - provider: Slack
supportedSecret: Slack API Token supportedSecret: Slack API Token
@@ -4224,7 +4224,7 @@
isPublic: true isPublic: true
isPrivateWithGhas: true isPrivateWithGhas: true
hasPushProtection: false hasPushProtection: false
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}' hasValidityCheck: false
isduplicate: false isduplicate: false
- provider: Yandex - provider: Yandex
supportedSecret: Yandex.Cloud API Key supportedSecret: Yandex.Cloud API Key

View File

@@ -1,5 +1,5 @@
{ {
"sha": "4bc2c75484abeca92df68432bf1a735a34f04466", "sha": "33706f4cc21d513d0337649024dc4e57dbe9f245",
"blob-sha": "8b8c921a94ef82f90298be6d4a7f963d48c2abcb", "blob-sha": "40aebd4d6ddd62fa47833df008290cc39fb8c0a4",
"targetFilename": "code-security/secret-scanning/introduction/supported-secret-scanning-patterns" "targetFilename": "code-security/secret-scanning/introduction/supported-secret-scanning-patterns"
} }