Skip to content

Commit 0e3b425

Browse files
committed
fix(updating): scope checksum replacements to target object
SFW_FREE_CHECKSUMS and SFW_ENTERPRISE_CHECKSUMS share platform keys (e.g. 'linux-arm64'). Add objectName parameter to replaceChecksumValue that scopes regex replacement within the target object block, preventing cross-object mismatches.
1 parent b89b953 commit 0e3b425

1 file changed

Lines changed: 41 additions & 7 deletions

File tree

.claude/hooks/setup-security-tools/update.mts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,53 @@ function replaceChecksumValue(
130130
assetName: string,
131131
oldHash: string,
132132
newHash: string,
133+
objectName?: string,
133134
): string {
134135
// Match the specific asset line in a checksums object.
135136
const escaped = assetName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
136-
const pattern = new RegExp(
137+
const multiLine = new RegExp(
137138
`('${escaped}':\\s*\\n\\s*')${oldHash}'`,
138139
)
139-
if (pattern.test(source)) {
140-
return source.replace(pattern, `$1${newHash}'`)
141-
}
142-
// Single-line format: 'asset-name': 'hash',
143140
const singleLine = new RegExp(
144141
`('${escaped}':\\s*')${oldHash}'`,
145142
)
143+
// When objectName is provided, scope the replacement to that object block
144+
// to avoid ambiguity when multiple objects share the same platform keys
145+
// (e.g. SFW_FREE_CHECKSUMS and SFW_ENTERPRISE_CHECKSUMS both use 'linux-arm64').
146+
if (objectName) {
147+
const objStart = source.indexOf(`const ${objectName}`)
148+
if (objStart !== -1) {
149+
const braceStart = source.indexOf('{', objStart)
150+
if (braceStart !== -1) {
151+
// Find the matching closing brace.
152+
let depth = 0
153+
let braceEnd = -1
154+
for (let i = braceStart; i < source.length; i += 1) {
155+
if (source[i] === '{') depth += 1
156+
else if (source[i] === '}') {
157+
depth -= 1
158+
if (!depth) {
159+
braceEnd = i + 1
160+
break
161+
}
162+
}
163+
}
164+
if (braceEnd !== -1) {
165+
let block = source.slice(objStart, braceEnd)
166+
if (multiLine.test(block)) {
167+
block = block.replace(multiLine, `$1${newHash}'`)
168+
} else {
169+
block = block.replace(singleLine, `$1${newHash}'`)
170+
}
171+
return source.slice(0, objStart) + block + source.slice(braceEnd)
172+
}
173+
}
174+
}
175+
}
176+
// Unscoped fallback: replace first match in entire source.
177+
if (multiLine.test(source)) {
178+
return source.replace(multiLine, `$1${newHash}'`)
179+
}
146180
return source.replace(singleLine, `$1${newHash}'`)
147181
}
148182

@@ -424,7 +458,7 @@ async function updateSfw(source: string): Promise<{
424458
if (free.changed) {
425459
for (const { 0: platform, 1: hash } of Object.entries(free.checksums)) {
426460
if (currentFree[platform] && currentFree[platform] !== hash) {
427-
updated = replaceChecksumValue(updated, platform, currentFree[platform]!, hash)
461+
updated = replaceChecksumValue(updated, platform, currentFree[platform]!, hash, 'SFW_FREE_CHECKSUMS')
428462
}
429463
}
430464
results.push({ tool: 'sfw-free', skipped: false, updated: true, reason: 'checksums updated' })
@@ -444,7 +478,7 @@ async function updateSfw(source: string): Promise<{
444478
if (enterprise.changed) {
445479
for (const { 0: platform, 1: hash } of Object.entries(enterprise.checksums)) {
446480
if (currentEnterprise[platform] && currentEnterprise[platform] !== hash) {
447-
updated = replaceChecksumValue(updated, platform, currentEnterprise[platform]!, hash)
481+
updated = replaceChecksumValue(updated, platform, currentEnterprise[platform]!, hash, 'SFW_ENTERPRISE_CHECKSUMS')
448482
}
449483
}
450484
results.push({ tool: 'sfw-enterprise', skipped: false, updated: true, reason: 'checksums updated' })

0 commit comments

Comments
 (0)