diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e74badf..3e93161 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -83,7 +83,7 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} - type=sha,prefix={{branch}}- + type=sha type=raw,value=staging,enable=${{ github.ref == 'refs/heads/main' }} type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} @@ -92,7 +92,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha @@ -103,14 +103,21 @@ jobs: name: Security Scanning runs-on: ubuntu-latest needs: build + if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v4 + - name: Extract first image tag + id: first-tag + run: | + FIRST_TAG=$(echo "${{ needs.build.outputs.image-tag }}" | head -n 1) + echo "tag=$FIRST_TAG" >> $GITHUB_OUTPUT + - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: - image-ref: ${{ needs.build.outputs.image-tag }} + image-ref: ${{ steps.first-tag.outputs.tag }} format: 'sarif' output: 'trivy-results.sarif' diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index e77ff40..bc4ed03 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -47,8 +47,8 @@ jobs: uses: trufflesecurity/trufflehog@main with: path: ./ - base: main - head: HEAD + base: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || '' }} + head: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || '' }} extra_args: --debug --only-verified codeql: diff --git a/eslint.config.js b/eslint.config.js index ca991c6..447acee 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -28,7 +28,7 @@ module.exports = [ }, rules: { // Error prevention - 'no-unused-vars': ['error', { 'argsIgnorePattern': '^_', 'varsIgnorePattern': '^_' }], + 'no-unused-vars': ['error', { 'argsIgnorePattern': '^_', 'varsIgnorePattern': '^_', 'caughtErrorsIgnorePattern': '^_' }], 'no-console': 'warn', 'no-debugger': 'error', diff --git a/src/services/claudeService.js b/src/services/claudeService.js index 1d83ed9..5341937 100644 --- a/src/services/claudeService.js +++ b/src/services/claudeService.js @@ -1,6 +1,4 @@ -const { execFileSync, exec } = require('child_process'); -const { promisify } = require('util'); -const execAsync = promisify(exec); +const { execFileSync } = require('child_process'); // Use sync methods for file operations that need to be synchronous const fsSync = require('fs'); const path = require('path'); @@ -87,7 +85,7 @@ For real functionality, please configure valid GitHub and Claude API tokens.`; try { execFileSync('docker', ['inspect', dockerImageName], { stdio: 'ignore' }); logger.info({ dockerImageName }, 'Docker image already exists'); - } catch (e) { + } catch (_e) { logger.info({ dockerImageName }, 'Building Docker image for Claude Code runner'); execFileSync('docker', ['build', '-f', 'Dockerfile.claudecode', '-t', dockerImageName, '.'], { cwd: path.join(__dirname, '../..'), @@ -149,7 +147,7 @@ Please complete this task fully and autonomously.`; }; // Build docker run command - properly escape values for shell - const envArgs = Object.entries(envVars) + Object.entries(envVars) .filter(([_, value]) => value !== undefined && value !== '') .map(([key, value]) => { // Convert to string and escape shell special characters in the value diff --git a/test-results/jest/results.xml b/test-results/jest/results.xml index d352e74..8324e8b 100644 --- a/test-results/jest/results.xml +++ b/test-results/jest/results.xml @@ -1,33 +1,53 @@ - - - + + + + + + + + + + + + + - + - + - + + + + + + + + + + + - + - + - + - + @@ -36,33 +56,23 @@ - + - + - + - + - - - - - - - - - - - + @@ -70,4 +80,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/unit/services/claudeService.test.js b/test/unit/services/claudeService.test.js index 6a5fe51..b044ade 100644 --- a/test/unit/services/claudeService.test.js +++ b/test/unit/services/claudeService.test.js @@ -49,7 +49,7 @@ jest.mock('../../../src/utils/secureCredentials', () => ({ })); // Now require the module under test -const { execFileSync, exec } = require('child_process'); +const { execFileSync } = require('child_process'); const { writeFileSync } = require('fs'); const { promisify } = require('util'); const { sanitizeBotMentions } = require('../../../src/utils/sanitize'); @@ -92,7 +92,7 @@ describe('Claude Service', () => { process.env.NODE_ENV = 'production'; // Mock dependencies needed in production mode - execFileSync.mockImplementation((cmd, args, options) => { + execFileSync.mockImplementation((cmd, args, _options) => { if (args[0] === 'inspect') return '{}'; return 'mocked output'; }); @@ -142,7 +142,7 @@ describe('Claude Service', () => { process.env.NODE_ENV = 'production'; // Mock the Docker inspect to succeed - execFileSync.mockImplementation((cmd, args, options) => { + execFileSync.mockImplementation((cmd, args, _options) => { if (args[0] === 'inspect') return '{}'; if (args[0] === 'logs') return 'error logs'; if (args[0] === 'kill') return ''; @@ -192,24 +192,20 @@ describe('Claude Service', () => { process.env.NODE_ENV = 'production'; // Mock the Docker inspect to succeed - execFileSync.mockImplementation((cmd, args, options) => { + execFileSync.mockImplementation((cmd, args, _options) => { if (args[0] === 'inspect') return '{}'; return 'mocked output'; }); - // Make sure our original command is accessible - const longCommand = options.command; - // Capture file write calls - let capturedFilePath = null; - writeFileSync.mockImplementation((path, content, options) => { - capturedFilePath = path; + writeFileSync.mockImplementation((_path, _content, _options) => { + // File write is mocked }); // Call the original implementation try { await originalProcessCommand(options); - } catch (e) { + } catch (_e) { // Ignore errors, we just want to check if writeFileSync was called }