From 30ccdab8afe628bcc014a04ee77a86a4a2195276 Mon Sep 17 00:00:00 2001 From: gabspereira Date: Sun, 5 Apr 2026 20:16:52 +0000 Subject: [PATCH] chore(opencode-sandbox): add SSH config, git safe directory, and test setup --- .opencode-sandbox/Dockerfile | 4 ++ .opencode-sandbox/entrypoint.sh | 22 ++++++++ .opencode-sandbox/jest.config.js | 8 +++ .opencode-sandbox/package.json | 17 ++++++ .opencode-sandbox/tests/ssh.test.ts | 84 +++++++++++++++++++++++++++++ .opencode-sandbox/tsconfig.json | 15 ++++++ 6 files changed, 150 insertions(+) create mode 100644 .opencode-sandbox/jest.config.js create mode 100644 .opencode-sandbox/package.json create mode 100644 .opencode-sandbox/tests/ssh.test.ts create mode 100644 .opencode-sandbox/tsconfig.json diff --git a/.opencode-sandbox/Dockerfile b/.opencode-sandbox/Dockerfile index 8e6fa10..240ff12 100644 --- a/.opencode-sandbox/Dockerfile +++ b/.opencode-sandbox/Dockerfile @@ -10,6 +10,10 @@ RUN pacman -Syu --noconfirm && \ opencode \ && pacman -Scc --noconfirm +# Git safe directory system-wide config +RUN git config --system --add safe.directory /workspace +RUN git config --system --add safe.directory '*' + # Firewall script — blocks everything except your Gitea instance COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh diff --git a/.opencode-sandbox/entrypoint.sh b/.opencode-sandbox/entrypoint.sh index 111390c..82e417c 100644 --- a/.opencode-sandbox/entrypoint.sh +++ b/.opencode-sandbox/entrypoint.sh @@ -1,6 +1,28 @@ #!/bin/bash + +# Fix SSH directory and key permissions +chmod 700 /root/.ssh chmod 600 /root/.ssh/id_ed25519 + +# Add Gitea server to known_hosts (suppress errors if network unavailable) +ssh-keyscan -H git.processhub.work >> /root/.ssh/known_hosts 2>/dev/null || true + +# Allow outbound SSH to Gitea +GITEA_IP=$(getent hosts git.processhub.work | awk '{print $1}' | head -1) +if [ -n "$GITEA_IP" ]; then + iptables -A OUTPUT -p tcp --dport 22 -d "$GITEA_IP" -j ACCEPT 2>/dev/null || true +fi + +# Configure SSH to use the correct key export GIT_SSH_COMMAND="ssh -i /root/.ssh/id_ed25519 -o StrictHostKeyChecking=accept-new" + +# Configure git user git config --global user.email "gabriel.pereira@protonmail.com" git config --global user.name "gabspereira" + +# Configure git safe directory (system-wide + workspace specific) +git config --system --add safe.directory '*' +git config --global --add safe.directory /workspace + +# Run opencode exec opencode diff --git a/.opencode-sandbox/jest.config.js b/.opencode-sandbox/jest.config.js new file mode 100644 index 0000000..e9f9ead --- /dev/null +++ b/.opencode-sandbox/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + rootDir: '.', + testMatch: ['**/tests/**/*.test.ts'], + verbose: true, + forceExit: true, +} diff --git a/.opencode-sandbox/package.json b/.opencode-sandbox/package.json new file mode 100644 index 0000000..160b780 --- /dev/null +++ b/.opencode-sandbox/package.json @@ -0,0 +1,17 @@ +{ + "name": "opencode-sandbox", + "version": "1.0.0", + "private": true, + "scripts": { + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage" + }, + "devDependencies": { + "@types/jest": "29.5.12", + "@types/node": "20.11.0", + "jest": "29.7.0", + "ts-jest": "29.1.2", + "typescript": "5.3.3" + } +} diff --git a/.opencode-sandbox/tests/ssh.test.ts b/.opencode-sandbox/tests/ssh.test.ts new file mode 100644 index 0000000..31777a1 --- /dev/null +++ b/.opencode-sandbox/tests/ssh.test.ts @@ -0,0 +1,84 @@ +import { exec } from 'child_process' +import { promisify } from 'util' +import * as fs from 'fs' +import * as path from 'path' + +const execAsync = promisify(exec) + +describe('SSH/Gitea Integration', () => { + const SSH_DIR = '/root/.ssh' + const SSH_KEY = path.join(SSH_DIR, 'id_ed25519') + const KNOWN_HOSTS = path.join(SSH_DIR, 'known_hosts') + + describe('SSH Key Setup', () => { + test('SSH directory exists', () => { + expect(fs.existsSync(SSH_DIR)).toBe(true) + }) + + test('SSH directory has correct permissions (0700)', () => { + const stats = fs.statSync(SSH_DIR) + const mode = stats.mode & 0o777 + expect(mode).toBe(0o700) + }) + + test('SSH key file exists', () => { + expect(fs.existsSync(SSH_KEY)).toBe(true) + }) + + test('SSH key has correct permissions (0600)', () => { + const stats = fs.statSync(SSH_KEY) + const mode = stats.mode & 0o777 + expect(mode).toBe(0o600) + }) + }) + + describe('Gitea Server', () => { + test('known_hosts file exists', () => { + expect(fs.existsSync(KNOWN_HOSTS)).toBe(true) + }) + + test('known_hosts contains git.processhub.work', () => { + const content = fs.readFileSync(KNOWN_HOSTS, 'utf8') + expect(content).toContain('git.processhub.work') + }) + }) + + describe('Git Configuration', () => { + test('git user.email is configured', async () => { + const { stdout } = await execAsync('git config --global user.email') + expect(stdout.trim()).toBe('gabriel.pereira@protonmail.com') + }) + + test('git user.name is configured', async () => { + const { stdout } = await execAsync('git config --global user.name') + expect(stdout.trim()).toBe('gabspereira') + }) + }) + + describe('Gitea SSH Connection', () => { + test('SSH connection to Gitea succeeds', async () => { + try { + const { stdout, stderr } = await execAsync( + 'ssh -T -o ConnectTimeout=10 git@git.processhub.work', + { timeout: 15000 } + ) + const output = stdout + stderr + expect(output).toContain('successfully authenticated') + } catch (error: any) { + const output = error.stdout + error.stderr + expect(output).toContain('gabspereira') + expect(output).toContain('successfully authenticated') + } + }, 20000) + }) + + describe('Git Remote Access', () => { + test('Can access Gitea repository', async () => { + const { stdout, stderr } = await execAsync( + 'git ls-remote git@git.processhub.work:gabspereira/workspace.git HEAD', + { timeout: 15000 } + ) + expect(stdout).toMatch(/[a-f0-9]+\s+HEAD/) + }, 20000) + }) +}) diff --git a/.opencode-sandbox/tsconfig.json b/.opencode-sandbox/tsconfig.json new file mode 100644 index 0000000..0fcb584 --- /dev/null +++ b/.opencode-sandbox/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "types": ["node", "jest"] + }, + "include": ["tests/**/*"], + "exclude": ["node_modules"] +}