Skip to content

Commit 85bfbbf

Browse files
paustin01claude
andcommitted
feat: emit core.warning annotations for report-only rule violations (VER-123)
Walk extra_metadata.preflight_status.rules_evaluated on each deployment event response and emit GitHub Actions warning annotations for report-only failures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4bac2c8 commit 85bfbbf

3 files changed

Lines changed: 75 additions & 1 deletion

File tree

dist/index.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35115,6 +35115,33 @@ function writeSummary(eventType, version, status, scmSha, apiUrl, resourceId, en
3511535115
core.warning(`Failed to write summary: ${error instanceof Error ? error.message : String(error)}`);
3511635116
}
3511735117
}
35118+
/**
35119+
* Emit core.warning annotations for any report-only rule failures present in
35120+
* the API response extra_metadata.preflight_status.rules_evaluated list.
35121+
*
35122+
* Report-only rules never block a deployment but their violations should be
35123+
* visible as GitHub Actions annotations so teams can act on them.
35124+
*/
35125+
function emitReportOnlyWarnings(extraMetadata) {
35126+
const preflightStatus = extraMetadata?.preflight_status;
35127+
if (preflightStatus === null || preflightStatus === undefined) {
35128+
return;
35129+
}
35130+
const rulesEvaluated = preflightStatus?.rules_evaluated;
35131+
if (!Array.isArray(rulesEvaluated) || rulesEvaluated.length === 0) {
35132+
return;
35133+
}
35134+
const violations = rulesEvaluated.filter((rule) => rule.status === 'report_only' && rule.evaluation_result === 'failed');
35135+
if (violations.length === 0) {
35136+
return;
35137+
}
35138+
core.info(`⚠ ${violations.length} report-only warning(s)`);
35139+
for (const rule of violations) {
35140+
const ruleName = typeof rule.rule_name === 'string' ? rule.rule_name : String(rule.rule_name ?? 'unknown');
35141+
const errorMessage = typeof rule.error_message === 'string' ? rule.error_message : String(rule.error_message ?? 'no details');
35142+
core.warning(`Report-only rule violation: ${ruleName} — ${errorMessage}`);
35143+
}
35144+
}
3511835145
/**
3511935146
* Main action entrypoint
3512035147
*/
@@ -35212,6 +35239,8 @@ async function run() {
3521235239
core.warning('⚠️ API response missing id field - this may indicate an API issue');
3521335240
core.debug(`Full response: ${JSON.stringify(response, null, 2)}`);
3521435241
}
35242+
// Surface report-only rule warnings from preflight evaluation
35243+
emitReportOnlyWarnings(response.extra_metadata);
3521535244
// Set outputs
3521635245
core.setOutput('deployment_id', response.id || '');
3521735246
core.setOutput('version_id', response.version_id || '');

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,48 @@ function writeSummary(
110110
}
111111
}
112112

113+
interface ReportOnlyRule {
114+
rule_name?: unknown
115+
error_message?: unknown
116+
status?: unknown
117+
evaluation_result?: unknown
118+
}
119+
120+
/**
121+
* Emit core.warning annotations for any report-only rule failures present in
122+
* the API response extra_metadata.preflight_status.rules_evaluated list.
123+
*
124+
* Report-only rules never block a deployment but their violations should be
125+
* visible as GitHub Actions annotations so teams can act on them.
126+
*/
127+
function emitReportOnlyWarnings(extraMetadata: Record<string, unknown> | null | undefined): void {
128+
const preflightStatus = extraMetadata?.preflight_status
129+
if (preflightStatus === null || preflightStatus === undefined) {
130+
return
131+
}
132+
133+
const rulesEvaluated = (preflightStatus as Record<string, unknown>)?.rules_evaluated
134+
if (!Array.isArray(rulesEvaluated) || rulesEvaluated.length === 0) {
135+
return
136+
}
137+
138+
const violations = (rulesEvaluated as ReportOnlyRule[]).filter(
139+
(rule) => rule.status === 'report_only' && rule.evaluation_result === 'failed'
140+
)
141+
142+
if (violations.length === 0) {
143+
return
144+
}
145+
146+
core.info(`⚠ ${violations.length} report-only warning(s)`)
147+
148+
for (const rule of violations) {
149+
const ruleName = typeof rule.rule_name === 'string' ? rule.rule_name : String(rule.rule_name ?? 'unknown')
150+
const errorMessage = typeof rule.error_message === 'string' ? rule.error_message : String(rule.error_message ?? 'no details')
151+
core.warning(`Report-only rule violation: ${ruleName}${errorMessage}`)
152+
}
153+
}
154+
113155
/**
114156
* Main action entrypoint
115157
*/
@@ -239,6 +281,9 @@ async function run(): Promise<void> {
239281
core.debug(`Full response: ${JSON.stringify(response, null, 2)}`)
240282
}
241283

284+
// Surface report-only rule warnings from preflight evaluation
285+
emitReportOnlyWarnings(response.extra_metadata)
286+
242287
// Set outputs
243288
core.setOutput('deployment_id', response.id || '')
244289
core.setOutput('version_id', response.version_id || '')

0 commit comments

Comments
 (0)