Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .aiguard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
version: 1

context:
small:
include:
- ARCHITECTURE.md
- SNAPSHOT.md
- README.md
- pyproject.toml
- package.json
- frontend/package.json
- contracts/**
large:
roots: [backend, app, src, frontend]
exclude_dirs:
- .git
- .venv
- venv
- node_modules
- dist
- build
- .next
- __pycache__
- __pypackages__
- .pytest_cache
- .mypy_cache
- .ruff_cache
exclude_globs: ["**/*.min.js", "**/*.map"]
max_files: 220
max_kb_each: 64

evidence:
commands:
- git status --porcelain=v1 || true
- git diff || true
- python --version || true
- node --version || true
- npm --version || true

dlp:
enable: true
block_on_detect: true
mask: true
allowlist_files:
- ".env.example"
- "frontend/.env.example"

guard:
forbid_full_rewrite: true
allow_full_rewrite_globs:
- "core/aiguard.py"
- ".github/workflows/oceansguard.yml"


checks:
commands:
# =========================
# Backend (Python)
# =========================
- >
python -c "import os,sys,subprocess;
targets=[d for d in ('backend','app','src') if os.path.isdir(d)];
sys.exit(subprocess.call([sys.executable,'-m','compileall',*targets]) if targets else 0)"

- >
python -c "import os,sys,subprocess,importlib.util;
targets=[d for d in ('backend','app','src') if os.path.isdir(d)];
has=importlib.util.find_spec('ruff') is not None;
sys.exit(subprocess.call([sys.executable,'-m','ruff','check',*targets]) if (has and targets) else 0)"

- >
python -c "import os,sys,subprocess,importlib.util;
targets=[d for d in ('backend','app','src') if os.path.isdir(d)];
has=importlib.util.find_spec('mypy') is not None;
sys.exit(subprocess.call([sys.executable,'-m','mypy',*targets]) if (has and targets) else 0)"

- >
python -c "import os,sys,subprocess,importlib.util;
has=importlib.util.find_spec('pytest') is not None;
has_tests=any(os.path.isdir(p) for p in ('tests','backend/tests','app/tests','src/tests'));
sys.exit(subprocess.call([sys.executable,'-m','pytest','-q']) if (has and has_tests) else 0)"

# =========================
# Frontend (React)
# =========================
- >
python -c "import os,sys,subprocess;
d='frontend';
sys.exit(0 if not os.path.isdir(d) else (subprocess.call('npm ci --silent', cwd=d, shell=True) if os.path.exists(os.path.join(d,'package-lock.json')) else subprocess.call('npm install --silent', cwd=d, shell=True)))"

- >
python -c "import os,sys,subprocess;
d='frontend';
sys.exit(0 if not os.path.isdir(d) else subprocess.call('npm run build --silent', cwd=d, shell=True))"

output:
pack: ai_context_pack.md
audit: CHANGELOG_AI.md
testlog: ai_test_last.log
report_json: ai_check_report.json
27 changes: 17 additions & 10 deletions .github/workflows/oceansguard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,28 @@ jobs:
- name: Upgrade pip
run: python -m pip install --upgrade pip

# FastAPI / OpenAPI契約チェック用(未使用PJでも害なし)
- name: Install Python tooling (best-effort)
- name: Install tooling (best-effort)
run: |
pip install uvicorn fastapi || true
pip install pyyaml || true
pip install ruff mypy pytest || true
pip install uvicorn fastapi || true

# React がある場合に備えて:node_modules はnpm ci/build側で吸収
- name: OceansGuard init (idempotent)
- name: Resolve OceansGuard entry
id: og
run: |
python tools/OceansGuard/core/aiguard.py init
if [ -f "tools/OceansGuard/core/aiguard.py" ]; then
echo "ENTRY=tools/OceansGuard/core/aiguard.py" >> $GITHUB_OUTPUT
elif [ -f "core/aiguard.py" ]; then
echo "ENTRY=core/aiguard.py" >> $GITHUB_OUTPUT
else
echo "OceansGuard entry not found" >&2
exit 1
fi

- name: OceansGuard pack
- name: OceansGuard init (idempotent)
run: |
python tools/OceansGuard/core/aiguard.py pack
python "${{ steps.og.outputs.ENTRY }}" init --repo .

- name: OceansGuard check
- name: OceansGuard run (pack + check)
run: |
python tools/OceansGuard/core/aiguard.py check
python "${{ steps.og.outputs.ENTRY }}" run --repo . --task "CI guard" --strict
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "common"]
path = common
url = https://github.com/OceansCreative/OceansCommon.git
7 changes: 7 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ARCHITECTURE

- レイヤ構成
- 依存方向
- 外部I/O(API/DB)

_generated by OceansGuard init @ 2025-12-31T10:35:26_
107 changes: 59 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,61 @@
# README.md
# OceansGuard

OceansGuard は、生成AIによるコード変更を
**CI・契約・セキュリティで機械的に裁くためのガードレール**です。

## 目的
- AIにコードを書かせても事故らせない
- 人が説明・確認・判断しなくてよい開発
- どの言語・フレームワークでも共通運用

## 基本思想
- AIは「提案者」
- 正しさは「テスト・契約・ポリシー」が決める
- 通らない変更は採用されない

## 使い方(各プロジェクト側)
```bash
python path/to/aiguard.py init
python path/to/aiguard.py pack
python path/to/aiguard.py check

対応フェーズ

開発前 / 開発途中 / 開発後 すべて対応


---

## ③ あなたの「不可がほぼ無い」運用フロー(確定)
**どの案件でもこれだけ**



AIに投げる前 → ai:pack
AI差分適用後 → ai:check
通ったら → 採用


- 考えない
- 説明しない
- レビューしない

---

## ④ 最初のGit操作(推奨)
```bash
git add .
git commit -m "feat: initial OceansGuard core structure"
git tag v0.1.0
git push origin main --tags
AI-assisted development guardrails for any repository.

## What it solves
- AI-generated changes that accidentally drop existing code
- Lack of global context (only partial files shown)
- Forgetfulness / inconsistent constraints across sessions
- No test / lint guarantees
- Secret leakage (keys/tokens) into commits
- Risky full-rewrite changes

## Core commands

### init
Create minimal guard files in target repo (idempotent; no overwrite).

python core/aiguard.py init --repo .

### pack
Generate AI context pack (diff-first).
```
python core/aiguard.py pack --repo .
```
### check
Run guard checks + configured project checks and write reports.
```
python core/aiguard.py check --repo .
```
### run
Shortcut = pack + check.
```
python core/aiguard.py run --repo . --task "your task"
```
## Strict mode
--strict makes guardrails non-negotiable:
- requires PyYAML
- fails if checks.commands is empty
- fails if contracts/openapi.json is missing/empty
```
python core/aiguard.py run --repo . --task "CI guard" --strict
```

## Submodule usage (recommended)
In your target repository:
```
git submodule add https://github.com/OceansCreative/OceansGuard.git tools/OceansGuard
python tools/OceansGuard/core/aiguard.py init --repo .
python tools/OceansGuard/core/aiguard.py run --repo . --task "初回ガード適用"
```
## Outputs
- ai_context_pack.md: single file to paste into AI chat
- ai_test_last.log: raw execution logs
- ai_check_report.json: structured result for CI/PR gating

## Git hooks (prevent committing to main)
Install with:
```
python core/install_hooks.py --repo .
```
7 changes: 7 additions & 0 deletions SNAPSHOT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SNAPSHOT

- 現在の仕様
- 既知の制約
- 触ってはいけない領域

_generated by OceansGuard init @ 2025-12-31T10:35:26_
44 changes: 44 additions & 0 deletions ai_check_report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"tool": "OceansGuard",
"generated_at": "2025-12-31T10:57:48",
"repo": "C:\\Users\\kazus\\OneDrive\\ドキュメント\\GitHub\\OceansGuard",
"mode": "normal",
"checks": [
{
"index": 1,
"command": "python -c \"import os,sys,subprocess; targets=[d for d in ('backend','app','src') if os.path.isdir(d)]; sys.exit(subprocess.call([sys.executable,'-m','compileall',*targets]) if targets else 0)\"",
"exit_code": 0
},
{
"index": 2,
"command": "python -c \"import os,sys,subprocess,importlib.util; targets=[d for d in ('backend','app','src') if os.path.isdir(d)]; has=importlib.util.find_spec('ruff') is not None; sys.exit(subprocess.call([sys.executable,'-m','ruff','check',*targets]) if (has and targets) else 0)\"",
"exit_code": 0
},
{
"index": 3,
"command": "python -c \"import os,sys,subprocess,importlib.util; targets=[d for d in ('backend','app','src') if os.path.isdir(d)]; has=importlib.util.find_spec('mypy') is not None; sys.exit(subprocess.call([sys.executable,'-m','mypy',*targets]) if (has and targets) else 0)\"",
"exit_code": 0
},
{
"index": 4,
"command": "python -c \"import os,sys,subprocess,importlib.util; has=importlib.util.find_spec('pytest') is not None; has_tests=any(os.path.isdir(p) for p in ('tests','backend/tests','app/tests','src/tests')); sys.exit(subprocess.call([sys.executable,'-m','pytest','-q']) if (has and has_tests) else 0)\"",
"exit_code": 0
},
{
"index": 5,
"command": "python -c \"import os,sys,subprocess; d='frontend'; sys.exit(0 if not os.path.isdir(d) else (subprocess.call('npm ci --silent', cwd=d, shell=True) if os.path.exists(os.path.join(d,'package-lock.json')) else subprocess.call('npm install --silent', cwd=d, shell=True)))\"",
"exit_code": 0
},
{
"index": 6,
"command": "python -c \"import os,sys,subprocess; d='frontend'; sys.exit(0 if not os.path.isdir(d) else subprocess.call('npm run build --silent', cwd=d, shell=True))\"",
"exit_code": 0
}
],
"dlp_hits": [],
"guard": {
"full_rewrite": null
},
"openapi_contract": null,
"status": "pass"
}
Loading
Loading