-
Notifications
You must be signed in to change notification settings - Fork 0
chore: merge branches #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: copilot/custom-marketplace-action-setup
Are you sure you want to change the base?
Conversation
BREAKING CHANGE: src/index.js and src/copilot-loader.js now use ESM syntax Fixes critical mocking issues preventing 80% test coverage enforcement: - Converted src/index.js from require() to import/export statements - Converted src/copilot-loader.js to ESM for proper module mocking - Added "type": "module" to package.json for ESM support - Updated eslint.config.mjs to sourceType: 'module' (from 'commonjs') - Renamed .eslintrc.js -> .eslintrc.cjs and commitlint.config.js -> commitlint.config.cjs Security improvements: - Moved absolute path & path traversal validation BEFORE sanitization - Previously unreachable checks now properly enforce filename safety Test coverage enhancements: - Created __tests__/mocks.js with vi.hoisted() for proper ESM mocking - Added 4 new comprehensive test cases (34 total): - Absolute path validation - Permission request handlers (all 4 branches: read/write/shell/unknown) - Session event handlers (all 5 event types) - forceStop error handling - Achieved 99.34% statement, 94.64% branch, 100% function coverage - Removed unreachable regex global flag (gi -> i) to prevent state pollution Lefthook enforcement (pre-commit): - Format > Lint > Test pipeline with stage_fixed: true - Coverage thresholds (80% minimum) enforced via vitest.config.js - All checks pass via 'make ai-checks' Note: This is prerelease development; ESM is the standardized path forward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request performs a comprehensive migration from CommonJS to ES Modules (ESM) across the codebase, along with enhancements to testing infrastructure and development workflows. The migration affects all source files, test files, and related configurations.
Changes:
- Migrated all source files from CommonJS (
require/module.exports) to ESM (import/export) syntax - Enhanced test suite with comprehensive test cases and improved mocking strategy using Vitest
- Added code quality enforcement via coverage thresholds and pre-commit hooks
- Reorganized security validation to fail fast by checking for prompt injection before initializing Copilot client
Reviewed changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.js | Added inline dependency handling for @actions/* packages, excluded copilot-loader.js from coverage, and added 80% coverage thresholds |
| test-copilot-instructions.txt | New test instruction file with placeholder content |
| src/index.js | Migrated to ESM imports/exports, removed regex global flags, moved prompt injection validation earlier in flow, updated main module detection |
| src/copilot-loader.js | Converted to ESM export syntax |
| package.json | Added "type": "module" and changed test script to always run with coverage |
| eslint.config.mjs | Removed CommonJS-specific globals to align with ESM migration |
| commitlint.config.cjs | New configuration enforcing conventional commits with RAI attribution |
| tests/setup.js | Replaced Jest-based mocks with Vitest mocks (appears unused) |
| tests/mocks.js | New centralized mock definitions using vi.hoisted() pattern |
| tests/index.test.js | Significantly expanded test coverage with 30+ new test cases covering all major functions |
| .lefthook.yml | Added pre-commit test execution with coverage reporting |
| .eslintrc.cjs | New legacy ESLint configuration file (conflicts with existing flat config) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| run: npm run lint | ||
| stage_fixed: true | ||
| test: | ||
| run: npm run test -- --run --reporter=verbose |
Copilot
AI
Jan 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running the full test suite with coverage on every commit via the pre-commit hook can significantly slow down the commit process, especially as the test suite grows. This could frustrate developers and discourage frequent commits. Consider either: 1) running tests without coverage in the pre-commit hook (the CI will still enforce coverage thresholds), or 2) making the test hook optional/skippable for faster iteration during development.
| run: npm run test -- --run --reporter=verbose | |
| run: '[ -n "$SKIP_PRECOMMIT_TESTS" ] || npm run test -- --run --reporter=verbose' |
| import { vi, beforeAll } from 'vitest'; | ||
|
|
||
| if (!fs.promises) { | ||
| fs.promises = { | ||
| access: jest.fn().mockResolvedValue(undefined), | ||
| readFile: jest.fn().mockResolvedValue(''), | ||
| writeFile: jest.fn().mockResolvedValue(undefined), | ||
| appendFile: jest.fn().mockResolvedValue(undefined), | ||
| rm: jest.fn().mockResolvedValue(undefined), | ||
| mkdir: jest.fn().mockResolvedValue(undefined), | ||
| }; | ||
| } | ||
| beforeAll(() => { | ||
| process.env.INPUT_PRIVATE_TOKEN = 'test-token-12345'; | ||
| process.env.INPUT_FILENAME = ''; | ||
| process.env.INPUT_BRANCH = 'main'; | ||
| process.env.GITHUB_REPOSITORY = 'testowner/testrepo'; | ||
| process.env.GITHUB_ACTOR = 'testuser'; | ||
| process.env.GITHUB_REF = 'refs/heads/main'; | ||
| }); | ||
|
|
||
| vi.mock('@actions/core', () => ({ | ||
| getInput: vi.fn((name, opts) => { | ||
| const value = process.env[`INPUT_${name.toUpperCase()}`] || ''; | ||
| if (opts?.required && !value) { | ||
| throw new Error(`Input required and not supplied: ${name}`); | ||
| } | ||
| return value; | ||
| }), | ||
| setOutput: vi.fn(), | ||
| setFailed: vi.fn(), | ||
| error: vi.fn(), | ||
| warning: vi.fn(), | ||
| info: vi.fn(), | ||
| })); | ||
|
|
||
| vi.mock('@actions/exec', () => ({ | ||
| exec: vi.fn(async (cmd, args, opts) => { | ||
| if (args?.includes('diff-index')) { | ||
| return opts?.ignoreReturnCode ? 0 : 1; | ||
| } | ||
| return 0; | ||
| }), | ||
| })); | ||
|
|
||
| Object.defineProperty(fs, 'promises', { | ||
| value: { | ||
| access: jest.fn().mockResolvedValue(undefined), | ||
| readFile: jest.fn().mockResolvedValue(''), | ||
| writeFile: jest.fn().mockResolvedValue(undefined), | ||
| appendFile: jest.fn().mockResolvedValue(undefined), | ||
| rm: jest.fn().mockResolvedValue(undefined), | ||
| mkdir: jest.fn().mockResolvedValue(undefined), | ||
| vi.mock('@actions/github', () => ({ | ||
| context: { | ||
| repo: { | ||
| owner: 'testowner', | ||
| repo: 'testrepo', | ||
| }, | ||
| actor: 'testuser', | ||
| ref: 'refs/heads/main', | ||
| }, | ||
| writable: true, | ||
| configurable: true, | ||
| }); | ||
| getOctokit: vi.fn(() => ({ | ||
| rest: { | ||
| pulls: { | ||
| create: vi.fn(async () => ({ | ||
| data: { number: 42, html_url: 'https://github.com/test/repo/pull/42' }, | ||
| })), | ||
| }, | ||
| issues: { | ||
| addAssignees: vi.fn(async () => ({})), | ||
| }, | ||
| }, | ||
| })), | ||
| })); | ||
|
|
||
| vi.mock('../src/copilot-loader.js', () => ({ | ||
| getCopilotClient: vi.fn(async () => { | ||
| return class MockCopilotClient { | ||
| constructor() { | ||
| this.started = false; | ||
| } | ||
| async start() { | ||
| this.started = true; | ||
| } | ||
| async createSession() { | ||
| return { | ||
| sessionId: 'mock-session-123', | ||
| on: vi.fn(), | ||
| sendAndWait: vi.fn(async () => {}), | ||
| destroy: vi.fn(async () => {}), | ||
| }; | ||
| } | ||
| async stop() { | ||
| this.started = false; | ||
| } | ||
| async forceStop() { | ||
| this.started = false; | ||
| } | ||
| }; | ||
| }), | ||
| })); |
Copilot
AI
Jan 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This setup file appears to be unused. The vitest configuration doesn't reference it as a setup file, and the test file (__tests__/index.test.js) imports and uses mocks from mocks.js instead. Having unused mock setup code can cause confusion and increases maintenance burden. Consider removing this file if it's not needed, or if it should be used, add it to the vitest config as a setup file using the setupFiles option.
| /ignore\s+(all\s+)?previous\s+(instructions?|prompts?|commands?)/i, | ||
| /disregard\s+(all\s+)?previous\s+(instructions?|prompts?|commands?)/i, | ||
| /forget\s+(all\s+)?previous\s+(instructions?|prompts?|commands?)/i, | ||
| /new\s+(instructions?|prompts?|commands?):/i, | ||
| /system\s+(prompt|message|instruction):/i, | ||
| /you\s+are\s+now\s+(a|an)/i, | ||
| /from\s+now\s+on\s+you\s+(are|will)/i, | ||
| /\[SYSTEM\]/i, | ||
| /\[ADMIN\]/i, | ||
| /\[OVERRIDE\]/i, | ||
| /<\s*system\s*>/i, | ||
| /<\s*admin\s*>/i, |
Copilot
AI
Jan 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of the gi flags (global, case-insensitive) and replacement with just i (case-insensitive) changes the behavior of these regex patterns. Without the global flag, the patterns will stop after the first match, but since these are used in a test check (not for replacement), this is acceptable. However, this is a semantic change that should be verified - if the original global flag was intentional for some edge cases, removing it could affect detection accuracy.
| const injectionCheck = detectPromptInjection(instructions); | ||
| if (!injectionCheck.isValid) { | ||
| logger.error({ reason: injectionCheck.reason }, 'Prompt injection detected'); | ||
| throw new Error(`Security: ${injectionCheck.reason}`); | ||
| } |
Copilot
AI
Jan 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prompt injection check has been moved to occur before the Copilot client is initialized. This is a good security improvement as it fails fast, but it changes the error handling flow. Previously, if the client initialization failed, the injection check wouldn't run. Now the injection check always runs first. Ensure that any error handling logic depending on the previous order is updated accordingly.
| @@ -0,0 +1 @@ | |||
| Add tests for user service No newline at end of file | |||
Copilot
AI
Jan 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file appears to be a test fixture or example file with minimal content. The filename suggests it's meant to provide instructions for Copilot testing, but the content "Add tests for user service" is very generic and doesn't seem to relate to this action's actual functionality (which is about delegating tasks to Copilot, not a user service). Consider either removing this file if it's not needed, or updating the content to reflect actual testing instructions relevant to this repository.
| Add tests for user service | |
| Instructions for testing the Copilot task-delegation action: | |
| - Create a minimal workflow that uses this action to delegate a coding task to Copilot. | |
| - Provide a clear, single-sentence task description in the workflow input (for example, "Implement a function that reverses a string"). | |
| - Run the workflow and verify that: | |
| - The action sends the task description to Copilot. | |
| - Any required parameters (repository, ref, file paths) are correctly passed through. | |
| - The action handles Copilot responses and errors without failing the workflow unexpectedly. | |
| - Add automated tests (or integration checks) that cover: | |
| - Successful delegation of a task. | |
| - Handling of invalid or missing task descriptions. | |
| - Behavior when Copilot is unavailable or returns an error. |
| test('throws on absolute path', async () => { | ||
| const { validateFilename } = await import('../src/index.js'); | ||
| expect(() => validateFilename('/etc/passwd')).toThrow('Absolute paths are not allowed'); | ||
| }); |
Copilot
AI
Jan 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is validating filename behavior but is placed inside the validateFile test suite. It should be moved to the validateFilename describe block above (lines 55-77) where it logically belongs. This improves test organization and makes it easier to understand which function is being tested.
This pull request introduces foundational infrastructure for quality, automation, and documentation standards in the repository. It sets up automated CI/CD workflows, code linting and formatting, dependency management, documentation conventions, and agent configuration for high-level architectural documentation. These changes lay the groundwork for a maintainable, well-documented, and automated development process.
CI/CD and Quality Automation
ci.yml) that automates setup, formatting, linting, building, testing, code coverage reporting, and a quality gate to ensure all checks pass before merging.dependabot.ymlconfiguration to automate dependency update PRs for both GitHub Actions and npm packages, with scheduled weekly checks and labeling.Code Quality and Linting
.eslintrc.cjs) enforcing recommended linting rules, Prettier formatting, and custom rules for unused variables and console statements.Documentation and Agent Standards
Repository Ownership
@anchildress1for all files.