@@ -20,7 +20,7 @@ jobs:
|
||||
# need to use a token from a user with access to github/github for this step
|
||||
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
|
||||
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
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
- name: Create an issue in the docs-content repo
|
||||
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
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}}
|
||||
|
||||
@@ -130,6 +130,7 @@ jobs:
|
||||
--body '👋 humans. This PR was generated from docs-internal/.github/workflows/delete-orphan-translation-files.yml.
|
||||
' \
|
||||
--repo "${{ matrix.language_repo }}" \
|
||||
--label "workflow-generated" \
|
||||
--head=$branch_name
|
||||
echo "Merge created PR..."
|
||||
retry_command gh pr merge --merge --auto --delete-branch "$branch_name"
|
||||
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
gh pr create \
|
||||
--title "Update CodeQL query tables" \
|
||||
--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.
|
||||
|
||||
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 }})
|
||||
|
||||
1
.github/workflows/moda-allowed-ips.yml
vendored
1
.github/workflows/moda-allowed-ips.yml
vendored
@@ -49,6 +49,7 @@ jobs:
|
||||
gh pr create \
|
||||
--title "Update list of allowed IPs" \
|
||||
--body 'This PR updates the list of allowed IPs in Moda. It is automatically generated.' \
|
||||
--label "workflow-generated" \
|
||||
--head=$branchname
|
||||
echo "Pull request created"
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
--title "Delete orphaned features ($date)" \
|
||||
--body "$body" \
|
||||
--repo github/docs-internal \
|
||||
--label docs-content-fr
|
||||
--label docs-content-fr,workflow-generated
|
||||
|
||||
- uses: ./.github/actions/slack-alert
|
||||
if: ${{ failure() && github.event_name == 'schedule' }}
|
||||
|
||||
2
.github/workflows/orphaned-files-check.yml
vendored
2
.github/workflows/orphaned-files-check.yml
vendored
@@ -105,7 +105,7 @@ jobs:
|
||||
--title "Delete orphaned files ($date)" \
|
||||
--body "$body" \
|
||||
--repo github/docs-internal \
|
||||
--label docs-content-fr
|
||||
--label docs-content-fr,workflow-generated
|
||||
|
||||
- uses: ./.github/actions/slack-alert
|
||||
if: ${{ failure() && github.event_name == 'schedule' }}
|
||||
|
||||
@@ -54,5 +54,5 @@ jobs:
|
||||
- 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
|
||||
`,
|
||||
labels: ['on track','open source', 'sme-review'],
|
||||
labels: ['on track','open source', 'sme-review', 'workflow-generated'],
|
||||
});
|
||||
|
||||
2
.github/workflows/sync-audit-logs.yml
vendored
2
.github/workflows/sync-audit-logs.yml
vendored
@@ -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).
|
||||
If CI does not pass or other problems arise, contact #docs-engineering on slack.' \
|
||||
--repo github/docs-internal \
|
||||
--label audit-log-pipeline \
|
||||
--label audit-log-pipeline,workflow-generated \
|
||||
--head=$branchname
|
||||
echo "Created pull request"
|
||||
|
||||
|
||||
2
.github/workflows/sync-codeql-cli.yml
vendored
2
.github/workflows/sync-codeql-cli.yml
vendored
@@ -108,7 +108,7 @@ jobs:
|
||||
|
||||
If CI does not pass or other problems arise, contact #docs-engineering on slack.' \
|
||||
--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
|
||||
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
|
||||
|
||||
2
.github/workflows/sync-openapi.yml
vendored
2
.github/workflows/sync-openapi.yml
vendored
@@ -114,7 +114,7 @@ jobs:
|
||||
|
||||
If CI does not pass or other problems arise, contact #docs-engineering on slack.' \
|
||||
--repo github/docs-internal \
|
||||
--label github-openapi-bot \
|
||||
--label github-openapi-bot,workflow-generated \
|
||||
--head=$branchname \
|
||||
|
||||
- uses: ./.github/actions/slack-alert
|
||||
|
||||
2
.github/workflows/sync-secret-scanning.yml
vendored
2
.github/workflows/sync-secret-scanning.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
|
||||
If CI does not pass or other problems arise, contact #docs-engineering on Slack.' \
|
||||
--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
|
||||
|
||||
- uses: ./.github/actions/slack-alert
|
||||
|
||||
@@ -4,6 +4,7 @@ labels:
|
||||
- enterprise deprecation
|
||||
- priority-1
|
||||
- time sensitive
|
||||
- workflow-generated
|
||||
---
|
||||
|
||||
# Deprecation steps for GHES releases
|
||||
|
||||
@@ -8,7 +8,7 @@ labels:
|
||||
- skip FR board
|
||||
- GHES {{ release-number }}
|
||||
- ghes-release-automation
|
||||
- rhythm of docs operations
|
||||
- workflow-generated
|
||||
---
|
||||
|
||||
This issue tracks Docs work for the GA release of GHES {{ release-number }}.
|
||||
|
||||
@@ -7,6 +7,7 @@ labels:
|
||||
- skip FR board
|
||||
- rhythm of docs operations
|
||||
- GHES {{ release-number }}
|
||||
- workflow-generated
|
||||
---
|
||||
|
||||
## Instructions for triage
|
||||
|
||||
@@ -7,6 +7,7 @@ labels:
|
||||
- skip FR board
|
||||
- GHES {{ release-number }}
|
||||
- rhythm of docs operations
|
||||
- workflow-generated
|
||||
---
|
||||
|
||||
## Instructions for triage
|
||||
|
||||
@@ -5,6 +5,7 @@ labels:
|
||||
- new-release
|
||||
- priority-0
|
||||
- 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.
|
||||
|
||||
@@ -4,6 +4,7 @@ labels:
|
||||
- Enterprise
|
||||
- priority-0
|
||||
- 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.
|
||||
|
||||
@@ -7,6 +7,7 @@ labels:
|
||||
- priority-0
|
||||
- skip FR board
|
||||
- rhythm of docs operations
|
||||
- workflow-generated
|
||||
---
|
||||
|
||||
## Instructions for triage
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { NextFunction, Response } from 'express'
|
||||
|
||||
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 { getReleaseNotes } from './get-release-notes'
|
||||
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.
|
||||
// So we want to use _all_ GHES versions when calculating next and previous releases.
|
||||
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).
|
||||
req.context.ghesReleases.forEach((release) => {
|
||||
|
||||
@@ -6,6 +6,8 @@ import { beforeAll, describe, expect, test } from 'vitest'
|
||||
import yaml from 'js-yaml'
|
||||
|
||||
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 {
|
||||
intro: string
|
||||
@@ -34,7 +36,7 @@ describe('lint enterprise release notes', () => {
|
||||
yamlContent = yaml.load(fileContents) as ReleaseNoteContent
|
||||
})
|
||||
|
||||
test('contains valid liquid', () => {
|
||||
test('contains valid liquid', async () => {
|
||||
const { intro, sections } = yamlContent
|
||||
let toLint: Record<string, string> = { intro }
|
||||
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) {
|
||||
if (!toLint[key]) continue
|
||||
// First check if liquid parses correctly
|
||||
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()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -381,54 +381,6 @@ export function AskAIResults({
|
||||
|
||||
return (
|
||||
<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
|
||||
key="ai-heading"
|
||||
as="h3"
|
||||
@@ -529,6 +481,54 @@ export function AskAIResults({
|
||||
></IconButton>
|
||||
</div>
|
||||
) : 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
|
||||
aria-live="assertive"
|
||||
style={{
|
||||
|
||||
@@ -266,12 +266,12 @@ export function SearchOverlay({
|
||||
|
||||
// Fetch initial search results on open
|
||||
useEffect(() => {
|
||||
if (searchOverlayOpen && (!isAskAIState || aiSearchError || aiCouldNotAnswer)) {
|
||||
if (searchOverlayOpen) {
|
||||
if (!searchEventGroupId.current) {
|
||||
searchEventGroupId.current = uuidv4()
|
||||
}
|
||||
updateAutocompleteResults(urlSearchInputQuery)
|
||||
} else if (isAskAIState || aiSearchError || aiCouldNotAnswer) {
|
||||
} else {
|
||||
// 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
|
||||
setSearchLoading(false)
|
||||
@@ -628,7 +628,10 @@ export function SearchOverlay({
|
||||
/>
|
||||
</Box>
|
||||
</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(
|
||||
@@ -885,36 +888,8 @@ function renderSearchGroups(
|
||||
const groups = []
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
if (showSpinner && !isInAskAIState) {
|
||||
groups.push(
|
||||
@@ -932,8 +907,8 @@ function renderSearchGroups(
|
||||
return groups
|
||||
}
|
||||
|
||||
// We want to show general search suggestions underneath the AI Response section if the AI Could no answer
|
||||
if ((generalSearchOptions.length && !isInAskAIState) || isInAskAIStateButNoAnswer) {
|
||||
// We want to show general search suggestions above the AI Response section if the AI could not answer
|
||||
if (generalSearchOptions.length || isInAskAIStateButNoAnswer) {
|
||||
const items = []
|
||||
for (let index = 0; index < generalSearchOptions.length; index++) {
|
||||
const option = generalSearchOptions[index]
|
||||
@@ -1034,17 +1009,43 @@ function renderSearchGroups(
|
||||
</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:
|
||||
// 1. We are in the AI could not answer state
|
||||
// 2. We are in the AI Search error state
|
||||
// 3. There are no AI suggestions to show in suggestions state
|
||||
if (
|
||||
!askAIState.aiCouldNotAnswer &&
|
||||
!isInAskAIState &&
|
||||
!askAIState.aiSearchError &&
|
||||
(!askAIState.isAskAIState ||
|
||||
generalSearchOptions.filter(
|
||||
(option) => !option.isViewAllResults && !option.isNoResultsFound,
|
||||
).length) &&
|
||||
generalSearchOptions.filter((option) => !option.isViewAllResults && !option.isNoResultsFound)
|
||||
.length &&
|
||||
aiOptionsWithUserInput.length
|
||||
) {
|
||||
groups.push(<ActionList.Divider key="bottom-divider" />)
|
||||
|
||||
@@ -1351,7 +1351,7 @@
|
||||
isPublic: true
|
||||
isPrivateWithGhas: true
|
||||
hasPushProtection: false
|
||||
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}'
|
||||
hasValidityCheck: false
|
||||
isduplicate: false
|
||||
- provider: Dropbox
|
||||
supportedSecret: Dropbox Short-Lived Access Token
|
||||
@@ -3531,7 +3531,7 @@
|
||||
isPublic: false
|
||||
isPrivateWithGhas: true
|
||||
hasPushProtection: true
|
||||
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}'
|
||||
hasValidityCheck: false
|
||||
isduplicate: false
|
||||
- provider: Shippo
|
||||
supportedSecret: Shippo Test API Token
|
||||
@@ -3543,7 +3543,7 @@
|
||||
isPublic: false
|
||||
isPrivateWithGhas: true
|
||||
hasPushProtection: false
|
||||
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}'
|
||||
hasValidityCheck: false
|
||||
isduplicate: false
|
||||
- provider: Shopee
|
||||
supportedSecret: Shopee Open Platform Partner Key
|
||||
@@ -3698,7 +3698,7 @@
|
||||
isPublic: true
|
||||
isPrivateWithGhas: true
|
||||
hasPushProtection: false
|
||||
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}'
|
||||
hasValidityCheck: false
|
||||
isduplicate: true
|
||||
- provider: Slack
|
||||
supportedSecret: Slack API Token
|
||||
@@ -4224,7 +4224,7 @@
|
||||
isPublic: true
|
||||
isPrivateWithGhas: true
|
||||
hasPushProtection: false
|
||||
hasValidityCheck: '{% ifversion fpt or ghes %}false{% else %}true{% endif %}'
|
||||
hasValidityCheck: false
|
||||
isduplicate: false
|
||||
- provider: Yandex
|
||||
supportedSecret: Yandex.Cloud API Key
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"sha": "4bc2c75484abeca92df68432bf1a735a34f04466",
|
||||
"blob-sha": "8b8c921a94ef82f90298be6d4a7f963d48c2abcb",
|
||||
"sha": "33706f4cc21d513d0337649024dc4e57dbe9f245",
|
||||
"blob-sha": "40aebd4d6ddd62fa47833df008290cc39fb8c0a4",
|
||||
"targetFilename": "code-security/secret-scanning/introduction/supported-secret-scanning-patterns"
|
||||
}
|
||||
Reference in New Issue
Block a user