sync: update from private repo (4c5a71f)
This commit is contained in:
parent
7049a874f3
commit
bea9fd67ee
@ -84,7 +84,7 @@ Return:
|
|||||||
{
|
{
|
||||||
"ok": true,
|
"ok": true,
|
||||||
"bytes_sent": 7,
|
"bytes_sent": 7,
|
||||||
"screen_after": "user@your-hostaao:~$ uptime\n 12:34 ...",
|
"screen_after": "swallow@aao:~$ uptime\n 12:34 ...",
|
||||||
"new_output_bytes": 120
|
"new_output_bytes": 120
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@ -22,7 +22,7 @@ if [ -z "$REPO" ]; then
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
echo " $0 myorg/myrepo"
|
echo " $0 myorg/myrepo"
|
||||||
echo " $0 myorg/myrepo http://192.168.1.100:9877"
|
echo " $0 myorg/myrepo http://10.0.0.10:9877"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Environment variables:"
|
echo "Environment variables:"
|
||||||
echo " GITEA_API_TOKEN (required) Gitea API token"
|
echo " GITEA_API_TOKEN (required) Gitea API token"
|
||||||
|
|||||||
@ -198,7 +198,7 @@ read -rp " 監視するリポジトリ (例: myorg/myrepo、スキップは空E
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$TARGET_REPO" ]; then
|
if [ -n "$TARGET_REPO" ]; then
|
||||||
read -rp " Orchestrator の外部URL (例: http://192.168.1.50:9876): " ORCH_URL
|
read -rp " Orchestrator の外部URL (例: http://10.0.0.10:9876): " ORCH_URL
|
||||||
ORCH_URL="${ORCH_URL:-http://localhost:9876}"
|
ORCH_URL="${ORCH_URL:-http://localhost:9876}"
|
||||||
|
|
||||||
# UI の repo プルダウンに出すため ui_repos へ登録
|
# UI の repo プルダウンに出すため ui_repos へ登録
|
||||||
|
|||||||
@ -22,12 +22,12 @@ gateway:
|
|||||||
shutdown_graceful_sec: 30
|
shutdown_graceful_sec: 30
|
||||||
backends:
|
backends:
|
||||||
- id: gpu-rtx-a
|
- id: gpu-rtx-a
|
||||||
endpoint: http://192.168.1.100:11434/v1
|
endpoint: http://10.0.0.10:11434/v1
|
||||||
model: qwen3:8b
|
model: qwen3:8b
|
||||||
max_slots: 4
|
max_slots: 4
|
||||||
api_key: ${GPU_RTX_A_KEY}
|
api_key: ${GPU_RTX_A_KEY}
|
||||||
- id: gpu-rtx-b
|
- id: gpu-rtx-b
|
||||||
endpoint: http://192.168.1.101:11434/v1
|
endpoint: http://10.0.0.10:11434/v1
|
||||||
model: qwen3:8b
|
model: qwen3:8b
|
||||||
max_slots: 4
|
max_slots: 4
|
||||||
virtual_keys:
|
virtual_keys:
|
||||||
|
|||||||
@ -12,13 +12,13 @@ provider:
|
|||||||
timeout_minutes: 15
|
timeout_minutes: 15
|
||||||
workers:
|
workers:
|
||||||
- id: gpu1
|
- id: gpu1
|
||||||
endpoint: http://192.168.1.100:11434/v1
|
endpoint: http://10.0.0.10:11434/v1
|
||||||
enabled: true
|
enabled: true
|
||||||
max_concurrency: 2
|
max_concurrency: 2
|
||||||
roles: [auto, fast]
|
roles: [auto, fast]
|
||||||
|
|
||||||
- id: gpu2
|
- id: gpu2
|
||||||
endpoint: http://192.168.1.101:11434/v1
|
endpoint: http://10.0.0.10:11434/v1
|
||||||
model: qwen3:14b
|
model: qwen3:14b
|
||||||
max_concurrency: 1
|
max_concurrency: 1
|
||||||
roles: [auto, quality]
|
roles: [auto, quality]
|
||||||
@ -34,7 +34,7 @@ provider:
|
|||||||
roles: [quality]
|
roles: [quality]
|
||||||
|
|
||||||
- id: gpu-reflection
|
- id: gpu-reflection
|
||||||
endpoint: http://192.168.1.102:11434/v1
|
endpoint: http://10.0.0.10:11434/v1
|
||||||
model: qwen3:8b
|
model: qwen3:8b
|
||||||
max_concurrency: 1
|
max_concurrency: 1
|
||||||
roles: [reflection]
|
roles: [reflection]
|
||||||
|
|||||||
@ -232,13 +232,13 @@ describe('Config API', () => {
|
|||||||
' model: shared-model',
|
' model: shared-model',
|
||||||
' workers:',
|
' workers:',
|
||||||
' - id: gpu1',
|
' - id: gpu1',
|
||||||
' endpoint: http://192.168.1.100:11434/v1',
|
' endpoint: http://10.0.0.10:11434/v1',
|
||||||
' model: qwen3:8b',
|
' model: qwen3:8b',
|
||||||
' roles: [auto, fast]',
|
' roles: [auto, fast]',
|
||||||
' enabled: true',
|
' enabled: true',
|
||||||
' api_key: super-secret-do-not-leak',
|
' api_key: super-secret-do-not-leak',
|
||||||
' - id: gpu2',
|
' - id: gpu2',
|
||||||
' endpoint: http://192.168.1.101:11434/v1',
|
' endpoint: http://10.0.0.10:11434/v1',
|
||||||
' enabled: false',
|
' enabled: false',
|
||||||
' retry:',
|
' retry:',
|
||||||
' max_attempts: 1',
|
' max_attempts: 1',
|
||||||
@ -252,7 +252,7 @@ describe('Config API', () => {
|
|||||||
const [w1, w2] = res.body.workers;
|
const [w1, w2] = res.body.workers;
|
||||||
expect(w1).toEqual({
|
expect(w1).toEqual({
|
||||||
id: 'gpu1',
|
id: 'gpu1',
|
||||||
endpoint: 'http://192.168.1.100:11434/v1',
|
endpoint: 'http://10.0.0.10:11434/v1',
|
||||||
model: 'qwen3:8b',
|
model: 'qwen3:8b',
|
||||||
roles: ['auto', 'fast'],
|
roles: ['auto', 'fast'],
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
@ -274,7 +274,7 @@ export async function callVisionModel(
|
|||||||
|
|
||||||
const toolsConfig = ctx.toolsConfig ?? {};
|
const toolsConfig = ctx.toolsConfig ?? {};
|
||||||
const visionModel = toolsConfig.visionModel ?? 'qwen2-vl:8b-instruct';
|
const visionModel = toolsConfig.visionModel ?? 'qwen2-vl:8b-instruct';
|
||||||
const visionBaseUrl = toolsConfig.visionBaseUrl ?? 'http://192.168.1.148:11434/v1';
|
const visionBaseUrl = toolsConfig.visionBaseUrl ?? 'http://10.0.0.10:11434/v1';
|
||||||
const visionTimeout = (toolsConfig.visionTimeout ?? 60) * 1000;
|
const visionTimeout = (toolsConfig.visionTimeout ?? 60) * 1000;
|
||||||
const visionMaxTokens = toolsConfig.visionMaxTokens ?? 1024;
|
const visionMaxTokens = toolsConfig.visionMaxTokens ?? 1024;
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ function makeContext(workspacePath: string): ToolContext {
|
|||||||
|
|
||||||
describe('sanitizeQuery', () => {
|
describe('sanitizeQuery', () => {
|
||||||
it('removes private IPv4 addresses', () => {
|
it('removes private IPv4 addresses', () => {
|
||||||
expect(sanitizeQuery('deploy to 192.168.1.100 nginx', {})).toBe('deploy to nginx');
|
expect(sanitizeQuery('deploy to 10.0.0.10 nginx', {})).toBe('deploy to nginx');
|
||||||
});
|
});
|
||||||
it('removes 10.x.x.x addresses', () => {
|
it('removes 10.x.x.x addresses', () => {
|
||||||
expect(sanitizeQuery('access 10.0.0.1 server', {})).toBe('access server');
|
expect(sanitizeQuery('access 10.0.0.1 server', {})).toBe('access server');
|
||||||
@ -44,11 +44,11 @@ describe('sanitizeQuery', () => {
|
|||||||
expect(sanitizeQuery('details about secret-project release', config)).toBe('details about release');
|
expect(sanitizeQuery('details about secret-project release', config)).toBe('details about release');
|
||||||
});
|
});
|
||||||
it('returns null when query becomes empty', () => {
|
it('returns null when query becomes empty', () => {
|
||||||
expect(sanitizeQuery('192.168.1.1', {})).toBeNull();
|
expect(sanitizeQuery('10.0.0.10', {})).toBeNull();
|
||||||
});
|
});
|
||||||
it('respects autoBlock toggles', () => {
|
it('respects autoBlock toggles', () => {
|
||||||
const config = { autoBlock: { privateIp: false } };
|
const config = { autoBlock: { privateIp: false } };
|
||||||
expect(sanitizeQuery('host 192.168.1.1 info', config)).toBe('host 192.168.1.1 info');
|
expect(sanitizeQuery('host 10.0.0.10 info', config)).toBe('host 10.0.0.10 info');
|
||||||
});
|
});
|
||||||
it('preserves public IPs', () => {
|
it('preserves public IPs', () => {
|
||||||
expect(sanitizeQuery('query 8.8.8.8 dns', {})).toBe('query 8.8.8.8 dns');
|
expect(sanitizeQuery('query 8.8.8.8 dns', {})).toBe('query 8.8.8.8 dns');
|
||||||
|
|||||||
@ -8,7 +8,7 @@ describe('isPrivateOrForbidden', () => {
|
|||||||
it('blocks IPv4 RFC1918 ranges', () => {
|
it('blocks IPv4 RFC1918 ranges', () => {
|
||||||
expect(isPrivateOrForbidden('10.0.0.1', 4)).toBe(true);
|
expect(isPrivateOrForbidden('10.0.0.1', 4)).toBe(true);
|
||||||
expect(isPrivateOrForbidden('172.16.0.1', 4)).toBe(true);
|
expect(isPrivateOrForbidden('172.16.0.1', 4)).toBe(true);
|
||||||
expect(isPrivateOrForbidden('192.168.1.1', 4)).toBe(true);
|
expect(isPrivateOrForbidden('10.0.0.10', 4)).toBe(true);
|
||||||
});
|
});
|
||||||
it('blocks IPv4 link-local and IMDS', () => {
|
it('blocks IPv4 link-local and IMDS', () => {
|
||||||
expect(isPrivateOrForbidden('169.254.169.254', 4)).toBe(true);
|
expect(isPrivateOrForbidden('169.254.169.254', 4)).toBe(true);
|
||||||
|
|||||||
@ -41,16 +41,16 @@ describe('net/ssrf-strict resolveAndCheck', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('rejects when DNS returns a private address (allowPrivate=false)', async () => {
|
it('rejects when DNS returns a private address (allowPrivate=false)', async () => {
|
||||||
const lookup: LookupFn = async () => [{ address: '192.168.1.5', family: 4 }];
|
const lookup: LookupFn = async () => [{ address: '10.0.0.10', family: 4 }];
|
||||||
const r = await resolveAndCheck({ host: 'evil.example.com', allowPrivate: false, lookup });
|
const r = await resolveAndCheck({ host: 'evil.example.com', allowPrivate: false, lookup });
|
||||||
expect(r.ok).toBe(false);
|
expect(r.ok).toBe(false);
|
||||||
if (!r.ok) expect(r.reason).toMatch(/Forbidden IP in DNS response/);
|
if (!r.ok) expect(r.reason).toMatch(/Forbidden IP in DNS response/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes when DNS returns a private address with allowPrivate=true', async () => {
|
it('passes when DNS returns a private address with allowPrivate=true', async () => {
|
||||||
const lookup: LookupFn = async () => [{ address: '192.168.1.5', family: 4 }];
|
const lookup: LookupFn = async () => [{ address: '10.0.0.10', family: 4 }];
|
||||||
const r = await resolveAndCheck({ host: 'host.lan', allowPrivate: true, lookup });
|
const r = await resolveAndCheck({ host: 'host.lan', allowPrivate: true, lookup });
|
||||||
expect(r).toEqual({ ok: true, ip: '192.168.1.5', family: 4 });
|
expect(r).toEqual({ ok: true, ip: '10.0.0.10', family: 4 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects when DNS returns no addresses', async () => {
|
it('rejects when DNS returns no addresses', async () => {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { ToolContext } from './src/engine/tools.js';
|
|||||||
import { mkdirSync } from 'fs';
|
import { mkdirSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
const BASE_URL = process.env['OLLAMA_BASE_URL'] ?? 'http://192.168.1.148:11434/v1';
|
const BASE_URL = process.env['OLLAMA_BASE_URL'] ?? 'http://10.0.0.10:11434/v1';
|
||||||
const MODEL = process.env['OLLAMA_MODEL'] ?? 'qwen3:8b';
|
const MODEL = process.env['OLLAMA_MODEL'] ?? 'qwen3:8b';
|
||||||
|
|
||||||
async function testLLMConnection() {
|
async function testLLMConnection() {
|
||||||
|
|||||||
@ -56,7 +56,7 @@ interface GatewayConfigShape {
|
|||||||
* when it's a finite integer-typed value, otherwise `fallback`. Without
|
* when it's a finite integer-typed value, otherwise `fallback`. Without
|
||||||
* this, `value={NaN ?? 1}` resolves to `NaN` (nullish-coalesce only
|
* this, `value={NaN ?? 1}` resolves to `NaN` (nullish-coalesce only
|
||||||
* traps null/undefined), and React renders the literal string "NaN"
|
* traps null/undefined), and React renders the literal string "NaN"
|
||||||
* into the input — see https://gitea.example.com/your-org/maestro for the
|
* into the input — see https://gitea.example.com/.../issues for the
|
||||||
* Phase 3c regression that motivated this helper.
|
* Phase 3c regression that motivated this helper.
|
||||||
*/
|
*/
|
||||||
function numberValue(n: unknown, fallback: number | ''): number | '' {
|
function numberValue(n: unknown, fallback: number | ''): number | '' {
|
||||||
|
|||||||
@ -231,7 +231,7 @@ export function LlmWorkersForm({ config, onChange, overriddenByEnv }: SectionFor
|
|||||||
disabledReason="OLLAMA_BASE_URL 環境変数で上書き中"
|
disabledReason="OLLAMA_BASE_URL 環境変数で上書き中"
|
||||||
placeholder={
|
placeholder={
|
||||||
isGateway
|
isGateway
|
||||||
? 'http://team-aao:9876/v1'
|
? 'http://gateway.example.com:9876/v1'
|
||||||
: 'http://localhost:11434/v1'
|
: 'http://localhost:11434/v1'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user