Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions actions/setup/js/safe_output_handler_manager.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const { generateMissingInfoSections } = require("./missing_info_formatter.cjs");
const { setCollectedMissings } = require("./missing_messages_helper.cjs");
const { writeSafeOutputSummaries } = require("./safe_output_summary.cjs");
const { getIssuesToAssignCopilot } = require("./create_issue.cjs");
const { validateTokenPermissions, generatePermissionErrorMessage, generatePermissionWarningMessage } = require("./token_permissions.cjs");

const DEFAULT_AGENTIC_CAMPAIGN_LABEL = "agentic-campaign";

Expand Down Expand Up @@ -826,6 +827,51 @@ async function main() {
return;
}

// Pre-flight token permission validation
// Extract operation types from messages to validate permissions
const operationTypes = new Set();
for (const message of agentOutput.items) {
if (message.type && messageHandlers.has(message.type)) {
operationTypes.add(message.type);
}
}

if (operationTypes.size > 0) {
core.info("\n=== Pre-flight Token Permission Validation ===");
core.info(`Validating permissions for ${operationTypes.size} operation type(s): ${Array.from(operationTypes).join(", ")}`);

try {
// Get repository context
const owner = context.repo.owner;
const repo = context.repo.repo;
const token = process.env.GITHUB_TOKEN || "";

// Validate token permissions
const validationResult = await validateTokenPermissions(token, owner, repo, Array.from(operationTypes));

// Check for missing required permissions (errors)
const failedOperations = validationResult.results.filter(r => !r.valid);
if (failedOperations.length > 0) {
const errorMessage = generatePermissionErrorMessage(validationResult.results, validationResult.tokenType);
core.error(errorMessage);
core.setFailed("Token lacks required permissions for safe output operations");
return;
}

// Check for missing optional permissions (warnings)
const operationsWithOptional = validationResult.results.filter(r => r.optional && r.optional.length > 0);
if (operationsWithOptional.length > 0) {
const warningMessage = generatePermissionWarningMessage(validationResult.results);
core.warning(warningMessage);
}

core.info("✅ Token permissions validated successfully");
} catch (error) {
// Log validation error but don't fail - permission check is best-effort
core.warning(`Permission validation failed (continuing with operation): ${getErrorMessage(error)}`);
}
}

// Process all messages in order of appearance
const processingResult = await processMessages(messageHandlers, agentOutput.items);

Expand Down
46 changes: 46 additions & 0 deletions actions/setup/js/safe_output_project_handler_manager.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
const { loadAgentOutput } = require("./load_agent_output.cjs");
const { getErrorMessage } = require("./error_helpers.cjs");
const { writeSafeOutputSummaries } = require("./safe_output_summary.cjs");
const { validateTokenPermissions, generatePermissionErrorMessage, generatePermissionWarningMessage } = require("./token_permissions.cjs");

/**
* Handler map configuration for project-related safe outputs
Expand Down Expand Up @@ -224,6 +225,51 @@ async function main() {
return;
}

// Pre-flight token permission validation for project operations
// Extract project operation types from messages
const projectOperationTypes = new Set();
for (const message of messages) {
if (message.type && messageHandlers.has(message.type)) {
projectOperationTypes.add(message.type);
}
}

if (projectOperationTypes.size > 0) {
core.info("\n=== Pre-flight Token Permission Validation (Project Operations) ===");
core.info(`Validating permissions for ${projectOperationTypes.size} project operation type(s): ${Array.from(projectOperationTypes).join(", ")}`);

try {
// Get repository context
const owner = context.repo.owner;
const repo = context.repo.repo;
const token = process.env.GH_AW_PROJECT_GITHUB_TOKEN || "";

// Validate token permissions
const validationResult = await validateTokenPermissions(token, owner, repo, Array.from(projectOperationTypes));

// Check for missing required permissions (errors)
const failedOperations = validationResult.results.filter(r => !r.valid);
if (failedOperations.length > 0) {
const errorMessage = generatePermissionErrorMessage(validationResult.results, validationResult.tokenType);
core.error(errorMessage);
core.setFailed("GH_AW_PROJECT_GITHUB_TOKEN lacks required permissions for project operations");
return;
}

// Check for missing optional permissions (warnings)
const operationsWithOptional = validationResult.results.filter(r => r.optional && r.optional.length > 0);
if (operationsWithOptional.length > 0) {
const warningMessage = generatePermissionWarningMessage(validationResult.results);
core.warning(warningMessage);
}

core.info("✅ Project token permissions validated successfully");
} catch (error) {
// Log validation error but don't fail - permission check is best-effort
core.warning(`Permission validation failed (continuing with operation): ${getErrorMessage(error)}`);
}
}

// Process messages
const { results, processedCount, temporaryProjectMap } = await processMessages(messageHandlers, messages);

Expand Down
Loading