Skip to content

Commit d9a6184

Browse files
Copilotdavid3107
andcommitted
Fix tag protection checks based on real API response
- Normalize scope patterns by stripping refs/tags/ prefix from API response - Implement proper tag_name_pattern rule validation in naming check - Compare policy naming operator, pattern, and negate against actual ruleset parameters Co-authored-by: david3107 <20040740+david3107@users.noreply.github.com>
1 parent 9a99bd3 commit d9a6184

File tree

3 files changed

+153
-31
lines changed

3 files changed

+153
-31
lines changed

dist/evaluators/repository/TagProtectionChecks.js

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,25 @@ class TagProtectionChecks {
8080
const excludePatterns = conditions?.ref_name?.exclude || [];
8181
const expectedInclude = policyScope.include || [];
8282
const expectedExclude = policyScope.exclude || [];
83+
// Normalize patterns - GitHub API returns patterns with refs/tags/ prefix
84+
const normalizePattern = (pattern) => {
85+
return pattern.replace(/^refs\/tags\//, "");
86+
};
87+
const normalizedIncludePatterns = includePatterns.map(normalizePattern);
88+
const normalizedExcludePatterns = excludePatterns.map(normalizePattern);
8389
// Check if all expected include patterns are present
84-
const missingIncludes = expectedInclude.filter((pattern) => !includePatterns.includes(pattern));
90+
const missingIncludes = expectedInclude.filter((pattern) => !normalizedIncludePatterns.includes(pattern));
8591
// Check if all expected exclude patterns are present
86-
const missingExcludes = expectedExclude.filter((pattern) => !excludePatterns.includes(pattern));
92+
const missingExcludes = expectedExclude.filter((pattern) => !normalizedExcludePatterns.includes(pattern));
8793
const passed = missingIncludes.length === 0 && missingExcludes.length === 0;
8894
return {
8995
passed,
9096
details: {
9197
expected_include: expectedInclude,
92-
actual_include: includePatterns,
98+
actual_include: normalizedIncludePatterns,
9399
missing_includes: missingIncludes,
94100
expected_exclude: expectedExclude,
95-
actual_exclude: excludePatterns,
101+
actual_exclude: normalizedExcludePatterns,
96102
missing_excludes: missingExcludes,
97103
},
98104
};
@@ -133,14 +139,45 @@ class TagProtectionChecks {
133139
};
134140
}
135141
checkNaming(policyNaming, ruleset) {
136-
// GitHub rulesets don't have a direct naming constraint rule
137-
// This would need to be implemented based on specific ruleset rules
138-
// For now, we'll return a placeholder
142+
const rules = ruleset.rules || [];
143+
// Find tag_name_pattern rule
144+
const tagNamePatternRule = rules.find((rule) => rule.type === "tag_name_pattern");
145+
if (!tagNamePatternRule) {
146+
return {
147+
passed: false,
148+
details: {
149+
message: "No tag_name_pattern rule found in ruleset",
150+
expected: policyNaming,
151+
actual: null,
152+
},
153+
};
154+
}
155+
const params = tagNamePatternRule.parameters || {};
156+
// Check if operator matches
157+
const operatorMatches = params.operator === policyNaming.operator;
158+
// Check if pattern matches
159+
const patternMatches = params.pattern === policyNaming.pattern;
160+
// Check if negate matches
161+
const negateMatches = params.negate === policyNaming.negate;
162+
const passed = operatorMatches && patternMatches && negateMatches;
139163
return {
140-
passed: true,
164+
passed,
141165
details: {
142-
message: "Naming constraint checking not fully implemented - requires custom rule analysis",
143-
policy: policyNaming,
166+
expected: {
167+
operator: policyNaming.operator,
168+
pattern: policyNaming.pattern,
169+
negate: policyNaming.negate,
170+
},
171+
actual: {
172+
operator: params.operator,
173+
pattern: params.pattern,
174+
negate: params.negate,
175+
},
176+
checks: {
177+
operator: operatorMatches,
178+
pattern: patternMatches,
179+
negate: negateMatches,
180+
},
144181
},
145182
};
146183
}

dist/index.js

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49310,19 +49310,25 @@ class TagProtectionChecks {
4931049310
const excludePatterns = conditions?.ref_name?.exclude || [];
4931149311
const expectedInclude = policyScope.include || [];
4931249312
const expectedExclude = policyScope.exclude || [];
49313+
// Normalize patterns - GitHub API returns patterns with refs/tags/ prefix
49314+
const normalizePattern = (pattern) => {
49315+
return pattern.replace(/^refs\/tags\//, "");
49316+
};
49317+
const normalizedIncludePatterns = includePatterns.map(normalizePattern);
49318+
const normalizedExcludePatterns = excludePatterns.map(normalizePattern);
4931349319
// Check if all expected include patterns are present
49314-
const missingIncludes = expectedInclude.filter((pattern) => !includePatterns.includes(pattern));
49320+
const missingIncludes = expectedInclude.filter((pattern) => !normalizedIncludePatterns.includes(pattern));
4931549321
// Check if all expected exclude patterns are present
49316-
const missingExcludes = expectedExclude.filter((pattern) => !excludePatterns.includes(pattern));
49322+
const missingExcludes = expectedExclude.filter((pattern) => !normalizedExcludePatterns.includes(pattern));
4931749323
const passed = missingIncludes.length === 0 && missingExcludes.length === 0;
4931849324
return {
4931949325
passed,
4932049326
details: {
4932149327
expected_include: expectedInclude,
49322-
actual_include: includePatterns,
49328+
actual_include: normalizedIncludePatterns,
4932349329
missing_includes: missingIncludes,
4932449330
expected_exclude: expectedExclude,
49325-
actual_exclude: excludePatterns,
49331+
actual_exclude: normalizedExcludePatterns,
4932649332
missing_excludes: missingExcludes,
4932749333
},
4932849334
};
@@ -49363,14 +49369,45 @@ class TagProtectionChecks {
4936349369
};
4936449370
}
4936549371
checkNaming(policyNaming, ruleset) {
49366-
// GitHub rulesets don't have a direct naming constraint rule
49367-
// This would need to be implemented based on specific ruleset rules
49368-
// For now, we'll return a placeholder
49372+
const rules = ruleset.rules || [];
49373+
// Find tag_name_pattern rule
49374+
const tagNamePatternRule = rules.find((rule) => rule.type === "tag_name_pattern");
49375+
if (!tagNamePatternRule) {
49376+
return {
49377+
passed: false,
49378+
details: {
49379+
message: "No tag_name_pattern rule found in ruleset",
49380+
expected: policyNaming,
49381+
actual: null,
49382+
},
49383+
};
49384+
}
49385+
const params = tagNamePatternRule.parameters || {};
49386+
// Check if operator matches
49387+
const operatorMatches = params.operator === policyNaming.operator;
49388+
// Check if pattern matches
49389+
const patternMatches = params.pattern === policyNaming.pattern;
49390+
// Check if negate matches
49391+
const negateMatches = params.negate === policyNaming.negate;
49392+
const passed = operatorMatches && patternMatches && negateMatches;
4936949393
return {
49370-
passed: true,
49394+
passed,
4937149395
details: {
49372-
message: "Naming constraint checking not fully implemented - requires custom rule analysis",
49373-
policy: policyNaming,
49396+
expected: {
49397+
operator: policyNaming.operator,
49398+
pattern: policyNaming.pattern,
49399+
negate: policyNaming.negate,
49400+
},
49401+
actual: {
49402+
operator: params.operator,
49403+
pattern: params.pattern,
49404+
negate: params.negate,
49405+
},
49406+
checks: {
49407+
operator: operatorMatches,
49408+
pattern: patternMatches,
49409+
negate: negateMatches,
49410+
},
4937449411
},
4937549412
};
4937649413
}

src/evaluators/repository/TagProtectionChecks.ts

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,22 @@ export class TagProtectionChecks {
105105
const expectedInclude = policyScope.include || [];
106106
const expectedExclude = policyScope.exclude || [];
107107

108+
// Normalize patterns - GitHub API returns patterns with refs/tags/ prefix
109+
const normalizePattern = (pattern: string): string => {
110+
return pattern.replace(/^refs\/tags\//, "");
111+
};
112+
113+
const normalizedIncludePatterns = includePatterns.map(normalizePattern);
114+
const normalizedExcludePatterns = excludePatterns.map(normalizePattern);
115+
108116
// Check if all expected include patterns are present
109117
const missingIncludes = expectedInclude.filter(
110-
(pattern: string) => !includePatterns.includes(pattern),
118+
(pattern: string) => !normalizedIncludePatterns.includes(pattern),
111119
);
112120

113121
// Check if all expected exclude patterns are present
114122
const missingExcludes = expectedExclude.filter(
115-
(pattern: string) => !excludePatterns.includes(pattern),
123+
(pattern: string) => !normalizedExcludePatterns.includes(pattern),
116124
);
117125

118126
const passed = missingIncludes.length === 0 && missingExcludes.length === 0;
@@ -121,10 +129,10 @@ export class TagProtectionChecks {
121129
passed,
122130
details: {
123131
expected_include: expectedInclude,
124-
actual_include: includePatterns,
132+
actual_include: normalizedIncludePatterns,
125133
missing_includes: missingIncludes,
126134
expected_exclude: expectedExclude,
127-
actual_exclude: excludePatterns,
135+
actual_exclude: normalizedExcludePatterns,
128136
missing_excludes: missingExcludes,
129137
},
130138
};
@@ -177,15 +185,55 @@ export class TagProtectionChecks {
177185
policyNaming: any,
178186
ruleset: any,
179187
): { passed: boolean; details: any } {
180-
// GitHub rulesets don't have a direct naming constraint rule
181-
// This would need to be implemented based on specific ruleset rules
182-
// For now, we'll return a placeholder
188+
const rules = ruleset.rules || [];
189+
190+
// Find tag_name_pattern rule
191+
const tagNamePatternRule = rules.find(
192+
(rule: any) => rule.type === "tag_name_pattern",
193+
);
194+
195+
if (!tagNamePatternRule) {
196+
return {
197+
passed: false,
198+
details: {
199+
message: "No tag_name_pattern rule found in ruleset",
200+
expected: policyNaming,
201+
actual: null,
202+
},
203+
};
204+
}
205+
206+
const params = tagNamePatternRule.parameters || {};
207+
208+
// Check if operator matches
209+
const operatorMatches = params.operator === policyNaming.operator;
210+
211+
// Check if pattern matches
212+
const patternMatches = params.pattern === policyNaming.pattern;
213+
214+
// Check if negate matches
215+
const negateMatches = params.negate === policyNaming.negate;
216+
217+
const passed = operatorMatches && patternMatches && negateMatches;
218+
183219
return {
184-
passed: true,
220+
passed,
185221
details: {
186-
message:
187-
"Naming constraint checking not fully implemented - requires custom rule analysis",
188-
policy: policyNaming,
222+
expected: {
223+
operator: policyNaming.operator,
224+
pattern: policyNaming.pattern,
225+
negate: policyNaming.negate,
226+
},
227+
actual: {
228+
operator: params.operator,
229+
pattern: params.pattern,
230+
negate: params.negate,
231+
},
232+
checks: {
233+
operator: operatorMatches,
234+
pattern: patternMatches,
235+
negate: negateMatches,
236+
},
189237
},
190238
};
191239
}

0 commit comments

Comments
 (0)