From bfaaaf1cec53b444594b033521b1cc26c7fdc8fd Mon Sep 17 00:00:00 2001 From: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 23:32:22 -0500 Subject: [PATCH] test(label-sync,app): pin the failure-list and source separators, the label-sync debug trace and the private-key trim A Stryker pass over the four src/ modules no earlier probe covered (adapters/app/settings.ts, cronJobs/handleCronJob.ts, cronJobs/labelSync.ts, utils/octokit.ts) left five behavioural survivors; each test here fails under exactly one of them and passes on main: - labelSync.ts:90 and handleCronJob.ts:31: a run where two creates are refused must fail naming both labels with their reasons, comma-separated, after logging 'running label-sync job' as sweep.test.ts already pins for the lgtm and sweep jobs. - labelSync.ts:45: with an org-level and a repo-level prow.yaml the debug line names both sources, comma-separated, instead of 'the built-in defaults only'. - settings.ts:40: a key carrying the newlines and spaces a secret file or heredoc leaves around it is trimmed after the \n unescape, as the docstring and docs/github-app.md promise. Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com> --- __tests__/adapters/app/platform.test.ts | 6 +++++ __tests__/cronJobTest/labelSync.test.ts | 29 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/__tests__/adapters/app/platform.test.ts b/__tests__/adapters/app/platform.test.ts index 32d02090..35853dbf 100644 --- a/__tests__/adapters/app/platform.test.ts +++ b/__tests__/adapters/app/platform.test.ts @@ -123,6 +123,12 @@ describe('settingsFromEnv', () => { it.each(['GITHUB_APP_ID', 'GITHUB_APP_PRIVATE_KEY', 'GITHUB_WEBHOOK_SECRET'])('requires %s', (name) => { expect(() => settingsFromEnv({ ...env, [name]: '' })).toThrow(`${name} must be set`) }) + + it('trims the newlines and spaces a secret file or heredoc leaves around the key', () => { + const s = settingsFromEnv({ ...env, GITHUB_APP_PRIVATE_KEY: '\n -----BEGIN PRIVATE KEY-----\\nabc\\n-----END PRIVATE KEY-----\n\n' }) + + expect(s.privateKey).toBe('-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----') + }) }) describe('memoryDeliveryStore', () => { diff --git a/__tests__/cronJobTest/labelSync.test.ts b/__tests__/cronJobTest/labelSync.test.ts index 2b0b5dc1..638ed041 100644 --- a/__tests__/cronJobTest/labelSync.test.ts +++ b/__tests__/cronJobTest/labelSync.test.ts @@ -253,6 +253,20 @@ describe('label-sync job', () => { expect(setFailed).toHaveBeenCalledWith(expect.stringContaining('1 label(s) could not be synced')) }) + it('names every refused label with its reason, comma-separated, when several writes fail', async () => { + serveConfig() + recordWrites([], name => (name === 'kind/bug' || name === 'lgtm' ? 422 : 201)) + vi.spyOn(core, 'error').mockImplementation(() => {}) + const debug = vi.spyOn(core, 'debug').mockImplementation(() => {}) + const setFailed = vi.spyOn(core, 'setFailed').mockImplementation(() => {}) + + await expect(handleCronJobs(dispatchContext())).resolves.toBeUndefined() + + expect(debug).toHaveBeenCalledWith('running label-sync job') + expect(setFailed).toHaveBeenCalledTimes(1) + expect(setFailed).toHaveBeenCalledWith(expect.stringMatching(/2 label\(s\) could not be synced: kind\/bug \(Validation Failed[^)]*\), lgtm \(Validation Failed[^)]*\)$/)) + }) + it('dry-run logs what would change and writes nothing', async () => { process.env['INPUT_DRY-RUN'] = 'true' serveConfig() @@ -312,6 +326,21 @@ describe('label-sync job', () => { expect(debug).toHaveBeenCalledWith(expect.stringContaining('labels from the built-in defaults only')) }) + it('names each configuration source the labels came from, comma-separated', async () => { + serveConfig() + // registered after serveConfig so this handler, not its 404, answers the org probe + const orgFile = structuredClone(labelFileContents) + orgFile.content = Buffer.from('labels:\n labels:\n - from-org\n').toString('base64') + server.use(http.get(utils.contentsUrl('Codertocat/.github:prow.yaml'), utils.mockResponse(200, orgFile))) + recordWrites([]) + const debug = vi.spyOn(core, 'debug').mockImplementation(() => {}) + vi.spyOn(core, 'info').mockImplementation(() => {}) + + await labelSync(dispatchContext()) + + expect(debug).toHaveBeenCalledWith(expect.stringContaining('labels from Codertocat/.github:prow.yaml, Codertocat/Hello-World:.github/prow.yaml')) + }) + it('records a write refused with a non-Error value by its string form', async () => { serveConfig() const writes = recordWrites([])