Browse Source

ci: harden private repository link gate

Tianyi Cui 2 months ago
parent
commit
a8879430f0

+ 17 - 4
scripts/verify-public-repository-links.spec.ts

@@ -2,18 +2,31 @@ import { describe, expect, it } from 'vitest'
 import { findInternalRepositoryReferences } from './verify-public-repository-links.ts'
 
 describe('public repository link policy', () => {
-  it('rejects internal repository references and accepts the public home', () => {
+  it('rejects encoded and case-varied internal identities without blocking public repositories', () => {
     const internalOwner = ['deepseek', 'harness'].join('-')
     const internalRepository = [internalOwner, internalOwner].join('/')
+    const encodedRepository = internalRepository.replaceAll('-', '%2D').replace('/', '%2F')
+    const htmlEncodedRepository = internalRepository.replace('/', '/')
+    const jsonEscapedRepository = internalRepository.replace('/', '\\/')
+    const unicodeEscapedRepository = internalRepository.replace('/', String.raw`\u002f`)
     const source = [
       'https://github.com/deepseek-ai/deepseek-harness-sdk',
-      `https://github.com/${internalRepository}/issues/1`,
-      `${internalOwner}#2`,
+      `https://github.com/${internalOwner}/cordis`,
+      `https://github.com/${internalRepository.toUpperCase()}/issues/1`,
+      `https://github.com/${encodedRepository}/issues/2`,
+      `https://github.com/${htmlEncodedRepository}/issues/3`,
+      `"https:\\/\\/github.com\\/${jsonEscapedRepository}\\/issues\\/4"`,
+      `"https:\\/\\/github.com\\/${unicodeEscapedRepository}\\/issues\\/5"`,
+      `${internalOwner.toUpperCase()}#6`,
     ].join('\n')
 
     expect(findInternalRepositoryReferences('subject.md', source)).toEqual([
-      { file: 'subject.md', line: 2 },
       { file: 'subject.md', line: 3 },
+      { file: 'subject.md', line: 4 },
+      { file: 'subject.md', line: 5 },
+      { file: 'subject.md', line: 6 },
+      { file: 'subject.md', line: 7 },
+      { file: 'subject.md', line: 8 },
     ])
   })
 })

+ 23 - 1
scripts/verify-public-repository-links.ts

@@ -10,6 +10,27 @@ const internalOwner = ['deepseek', 'harness'].join('-')
 const internalRepository = [internalOwner, internalOwner].join('/')
 const internalIssueShorthand = `${internalOwner}#`
 
+const namedReferenceCharacters: Readonly<Record<string, string>> = {
+  hyphen: '-',
+  num: '#',
+  sol: '/',
+}
+
+/** Normalize source spellings that render or decode to repository separators. */
+function canonicalReferenceText(source: string): string {
+  return source
+    .replaceAll('\\/', '/')
+    .replace(/\\u(0023|002d|002f)/gi, (_match, code: string) => String.fromCodePoint(Number.parseInt(code, 16)))
+    .replace(/%(23|2d|2f)/gi, (_match, code: string) => String.fromCodePoint(Number.parseInt(code, 16)))
+    .replace(/&#(?:(\d+)|x([\da-f]+));/gi, (entity, decimal: string | undefined, hexadecimal: string | undefined) => {
+      const code = Number.parseInt(decimal ?? hexadecimal ?? '', decimal === undefined ? 16 : 10)
+      return code === 35 || code === 45 || code === 47 ? String.fromCodePoint(code) : entity
+    })
+    .replace(/&(hyphen|num|sol);/gi, (entity, name: string) => namedReferenceCharacters[name.toLowerCase()] ?? entity)
+    .normalize('NFKC')
+    .toLowerCase()
+}
+
 /** One tracked reference to the internal repository. */
 export interface InternalRepositoryReference {
   /** Repository-relative file path. */
@@ -27,7 +48,8 @@ export interface InternalRepositoryReference {
 export function findInternalRepositoryReferences(file: string, source: string): InternalRepositoryReference[] {
   const references: InternalRepositoryReference[] = []
   for (const [index, line] of source.split('\n').entries()) {
-    if (line.includes(internalRepository) || line.includes(internalIssueShorthand)) {
+    const canonicalLine = canonicalReferenceText(line)
+    if (canonicalLine.includes(internalRepository) || canonicalLine.includes(internalIssueShorthand)) {
       references.push({ file, line: index + 1 })
     }
   }