From 24e9f0628f2f8bd86ae393f2b4c8093026b75304 Mon Sep 17 00:00:00 2001 From: Hyunseok Seo Date: Mon, 29 Dec 2025 19:13:43 -0500 Subject: [PATCH 1/4] fix(build-worker): use GitHub PAT from Parameter Store instead of env var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add getGitHubToken() function to retrieve PAT from common environment - GitHub PAT stored at /laco/cmn/github/pat/cloud-apps (cross-environment) - Support local development with GITHUB_PAT_CLOUD_APPS env var - Remove TODO comments and temporary GITHUB_TOKEN workaround This fixes the SSM parameter access issue where the build worker couldn't access the GitHub PAT needed for repository_dispatch API. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../chatops/slack-bot/src/shared/secrets.ts | 37 +++++++++++++++++++ .../slack-bot/src/workers/build/index.ts | 11 +----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/applications/chatops/slack-bot/src/shared/secrets.ts b/applications/chatops/slack-bot/src/shared/secrets.ts index 4de222f..50b04fa 100644 --- a/applications/chatops/slack-bot/src/shared/secrets.ts +++ b/applications/chatops/slack-bot/src/shared/secrets.ts @@ -71,3 +71,40 @@ export async function getSlackBotToken(): Promise { export async function getSlackSigningSecret(): Promise { return getSecret('slack/signing-secret'); } + +export async function getGitHubToken(): Promise { + // For local development, use environment variable + if (config.get().isLocal) { + const value = process.env.GITHUB_PAT_CLOUD_APPS; + if (value) { + logger.debug('GitHub PAT retrieved from environment'); + return value; + } + } + + // GitHub PAT is stored in common environment, not environment-specific + // Use direct parameter path instead of getSecret() which adds environment prefix + const parameterPath = '/laco/cmn/github/pat/cloud-apps'; + + try { + logger.debug('Fetching GitHub PAT from Parameter Store', { parameterPath }); + + const response = await ssmClient.send( + new GetParameterCommand({ + Name: parameterPath, + WithDecryption: true + }) + ); + + const value = response.Parameter?.Value; + if (!value) { + throw new Error(`GitHub PAT not found: ${parameterPath}`); + } + + logger.info('GitHub PAT retrieved successfully'); + return value; + } catch (error) { + logger.error('Failed to retrieve GitHub PAT', error as Error, { parameterPath }); + throw error; + } +} diff --git a/applications/chatops/slack-bot/src/workers/build/index.ts b/applications/chatops/slack-bot/src/workers/build/index.ts index b204a4b..4f5fa95 100644 --- a/applications/chatops/slack-bot/src/workers/build/index.ts +++ b/applications/chatops/slack-bot/src/workers/build/index.ts @@ -5,8 +5,7 @@ import axios from 'axios'; import { logger } from '../../shared/logger'; import { sendSlackResponse } from '../../shared/slack-client'; import { WorkerMessage } from '../../shared/types'; -// TODO: Re-enable when getParameter is implemented -// import { getParameter } from '../../shared/secrets'; +import { getGitHubToken } from '../../shared/secrets'; interface BuildCommand { component: string; // router, echo, deploy, status, all @@ -50,14 +49,8 @@ async function triggerGitHubWorkflow(params: { response_url: string; user: string; }): Promise { - // TODO: Re-enable when getParameter is implemented // Get GitHub token from Parameter Store - // const githubToken = await getParameter('/laco/cmn/github/pat/cloud-apps'); - const githubToken = process.env.GITHUB_TOKEN; - - if (!githubToken) { - throw new Error('GITHUB_TOKEN environment variable is required (temporary workaround until getParameter is implemented)'); - } + const githubToken = await getGitHubToken(); const owner = 'llamandcoco'; const repo = 'cloud-apps'; From b324c29baa1352815166a74af239dade01d7e5c0 Mon Sep 17 00:00:00 2001 From: Hyunseok Seo Date: Mon, 29 Dec 2025 20:03:01 -0500 Subject: [PATCH 2/4] Update applications/chatops/slack-bot/src/shared/secrets.ts --- applications/chatops/slack-bot/src/shared/secrets.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/applications/chatops/slack-bot/src/shared/secrets.ts b/applications/chatops/slack-bot/src/shared/secrets.ts index 50b04fa..f62ce54 100644 --- a/applications/chatops/slack-bot/src/shared/secrets.ts +++ b/applications/chatops/slack-bot/src/shared/secrets.ts @@ -73,15 +73,6 @@ export async function getSlackSigningSecret(): Promise { } export async function getGitHubToken(): Promise { - // For local development, use environment variable - if (config.get().isLocal) { - const value = process.env.GITHUB_PAT_CLOUD_APPS; - if (value) { - logger.debug('GitHub PAT retrieved from environment'); - return value; - } - } - // GitHub PAT is stored in common environment, not environment-specific // Use direct parameter path instead of getSecret() which adds environment prefix const parameterPath = '/laco/cmn/github/pat/cloud-apps'; From 680a0171605b08e4747a0f3a9cc45d26a830814c Mon Sep 17 00:00:00 2001 From: Hyunseok Seo Date: Mon, 29 Dec 2025 20:03:06 -0500 Subject: [PATCH 3/4] Update applications/chatops/slack-bot/src/shared/secrets.ts --- applications/chatops/slack-bot/src/shared/secrets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/chatops/slack-bot/src/shared/secrets.ts b/applications/chatops/slack-bot/src/shared/secrets.ts index f62ce54..d7bbb90 100644 --- a/applications/chatops/slack-bot/src/shared/secrets.ts +++ b/applications/chatops/slack-bot/src/shared/secrets.ts @@ -92,7 +92,7 @@ export async function getGitHubToken(): Promise { throw new Error(`GitHub PAT not found: ${parameterPath}`); } - logger.info('GitHub PAT retrieved successfully'); + logger.info('GitHub PAT retrieved successfully', { parameterPath: '/laco/cmn/github/pat/cloud-apps' }); return value; } catch (error) { logger.error('Failed to retrieve GitHub PAT', error as Error, { parameterPath }); From 2cdeae51ca6ee3482f63f22a2f41e771c2d7693c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 20:38:43 -0500 Subject: [PATCH 4/4] Add caching to getGitHubToken() to match getSecret() pattern (#13) - Initial plan - feat: add caching to getGitHubToken() function - fix: use parameterPath variable instead of hardcoded value in log --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: llama90 <6668548+llama90@users.noreply.github.com> --- .../chatops/slack-bot/src/shared/secrets.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/applications/chatops/slack-bot/src/shared/secrets.ts b/applications/chatops/slack-bot/src/shared/secrets.ts index d7bbb90..4877c10 100644 --- a/applications/chatops/slack-bot/src/shared/secrets.ts +++ b/applications/chatops/slack-bot/src/shared/secrets.ts @@ -73,6 +73,15 @@ export async function getSlackSigningSecret(): Promise { } export async function getGitHubToken(): Promise { + const cacheKey = 'github-pat'; + + // Check cache first + const cached = secretCache.get(cacheKey); + if (cached && cached.expiresAt > Date.now()) { + logger.debug('GitHub PAT retrieved from cache'); + return cached.value; + } + // GitHub PAT is stored in common environment, not environment-specific // Use direct parameter path instead of getSecret() which adds environment prefix const parameterPath = '/laco/cmn/github/pat/cloud-apps'; @@ -92,7 +101,13 @@ export async function getGitHubToken(): Promise { throw new Error(`GitHub PAT not found: ${parameterPath}`); } - logger.info('GitHub PAT retrieved successfully', { parameterPath: '/laco/cmn/github/pat/cloud-apps' }); + // Cache the GitHub PAT + secretCache.set(cacheKey, { + value, + expiresAt: Date.now() + CACHE_TTL + }); + + logger.info('GitHub PAT retrieved successfully', { parameterPath }); return value; } catch (error) { logger.error('Failed to retrieve GitHub PAT', error as Error, { parameterPath });