seokang-sk 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.MD CHANGED
@@ -12,7 +12,7 @@
12
12
  - [Node.js](https://nodejs.org/) 20 이상
13
13
  - [Git](https://git-scm.com/downloads)
14
14
 
15
- DB 영향 구현을 수행하는 owner는 [GitHub CLI](https://cli.github.com/)도 설치하고 `gh auth login`으로 본인 계정을 연결해야 합니다. 다른 사용자, 미인증 상태, GitHub CLI가 없는 환경은 DB 영향 구현이 자동 차단됩니다.
15
+ Git write, 배포, DB 영향 구현을 수행하려면 [GitHub CLI](https://cli.github.com/)도 설치하고 `gh auth login`으로 계정을 연결해야 합니다. 숫자형 GitHub user ID로 OWNER/NON_OWNER를 구분하며, 미인증 상태나 GitHub CLI가 없는 환경은 write/deploy가 자동 차단됩니다.
16
16
 
17
17
  Windows에서는 Git을 설치할 때 함께 제공되는 **Git Bash**를 사용하세요. macOS에서는 **터미널**을 사용하면 됩니다.
18
18
 
@@ -59,6 +59,18 @@ sk help
59
59
 
60
60
  ## 프로젝트에서 사용하기
61
61
 
62
+ ### selink-lab 친구 계정으로 개발하기
63
+
64
+ GitHub Free에서는 repository별 최소 권한을 적용합니다. `km-*` 4개는 접근 없음, `seokang-codex-setting`은 Read 전용·fork 금지, 나머지 승인된 4개만 개인 private fork와 PR을 허용합니다. SeoKang OWNER는 `fork-contributors` team에 넣지 않습니다.
65
+
66
+ 새 스레드의 첫 작업에서는 OWNER가 열린 원본 PR을 먼저 확인하고, NON_OWNER는 `selink-lab` upstream default branch를 `--ff-only`로 갱신합니다. `$sk-git`은 NON_OWNER branch의 기존 PR을 확인한 뒤 없으면 제목·본문을 만들어 PR까지 자동 생성합니다.
67
+
68
+ `$sk-git`은 add 전 worktree와 commit 전 staged index를 검사하며, 새 secret 파일이나 고신뢰 token을 탐지하면 로컬 파일을 삭제하지 않고 commit/push를 hard-fail합니다.
69
+
70
+ 처음 설치부터 fork, 원격 저장소 확인, 실제 스킬 호출, PR 생성까지의 전체 순서는 [친구 계정 private fork 개발 가이드](docs/setup/fork-contributor-guide.md)를 따릅니다.
71
+
72
+ Organization owner가 유지할 권한·team·Actions·2FA 기준은 [selink-lab GitHub Free 협업 설정](docs/setup/github-free-collaboration.md)에 정리되어 있습니다.
73
+
62
74
  ### 이미 있는 프로젝트에 적용
63
75
 
64
76
  터미널에서 프로젝트 폴더로 이동한 뒤 아래 명령을 실행합니다.
@@ -218,6 +230,7 @@ sk status
218
230
  - UI runtime router 체크: `node scripts/check_ui_runtime_router.mjs`
219
231
  - automation safety 체크: `node scripts/check_automation_safety.mjs`
220
232
  - operator identity guard 체크: `node scripts/check_operator_guard.mjs`
233
+ - deploy actor guard 체크: `node scripts/check_deploy_actor_guard.mjs`
221
234
  - npm 배포 범위 판정: `node scripts/check_npm_release_scope.mjs --json`
222
235
  - npm 배포 범위 smoke: `node scripts/check_npm_release_scope_smoke.mjs`
223
236
  - 전체 하네스: `npm run check:harness`
@@ -249,6 +262,10 @@ Windows Git Bash에서는 사용자 경로에 맞춰 `cd /c/Users/<user>/.agents
249
262
  - `sk status --cwd /path/to/project`: 다른 프로젝트 상태 확인
250
263
  - `sk identity status`: 현재 GitHub operator 상태 확인
251
264
  - `sk guard implementation --db-impact`: DB 영향 구현 owner preflight
265
+ - `sk guard git --action push --branch <name> --repo <name>`: repository/branch/action별 Git write preflight
266
+ - `sk guard stage pre-add|pre-commit <path ...>`: intended commit path와 Git index 일치 검사
267
+ - `sk guard secrets --worktree` / `--staged` / `--outbound --remote origin`: add, commit, push 직전 secret hard-fail
268
+ - `sk guard deploy --environment <name> --artifact <type> --action <action> --db-impact-status <status>`: 배포 권한 preflight
252
269
  - [상세 CLI 가이드](docs/setup/sk-cli-guide.md)를 기준 문서로 사용
253
270
 
254
271
  ---
@@ -393,9 +410,23 @@ sk search "reviewer"
393
410
  - 일반 서버 프로젝트: 원격 서버/NAS 업로드 + 재시작
394
411
  - `.agents/skills` 같은 `seokang-skill` 프로젝트: `npm publish`
395
412
 
413
+ 배포 권한은 아래처럼 분리합니다.
414
+
415
+ - NON_OWNER: 개인 private fork의 작업 branch push와 `selink-lab` 원본 PR까지만 허용. 모든 배포 mutation 차단
416
+ - OWNER: main/master write와 merge, production 배포, npm publish, rollback, tag/release 허용
417
+ - UNKNOWN: Git write와 모든 배포 차단
418
+
419
+ 모든 배포 스크립트는 build/upload/restart/publish 전에 `sk guard deploy`를 실행합니다. local/preview/staging/production 구분과 관계없이 실제 배포 mutation은 OWNER만 진행합니다. `DEPLOY_ISOLATED`와 `DEPLOY_ISOLATION_EVIDENCE`는 기존 local config 호환 필드이며 NON_OWNER 권한을 열지 않습니다.
420
+
421
+ 이 로컬 guard는 실수 방지층입니다. GitHub Free private 저장소의 실제 차단은 `selink-lab` 원본 Read 권한, 개인 private fork/PR, OWNER만 보유한 SSH/npm/DB/API/CDN credential로 구성합니다. fork PR Actions에는 write token, secrets, variables를 전달하지 않고 OWNER 승인 후 workflow를 실행합니다.
422
+
396
423
  예시 설정 파일:
397
424
 
398
425
  ```env
426
+ DEPLOY_ENVIRONMENT=production
427
+ DEPLOY_DB_IMPACT_STATUS=unknown
428
+ DEPLOY_ISOLATED=false
429
+ DEPLOY_ISOLATION_EVIDENCE=
399
430
  REMOTE_HOST=your-host
400
431
  REMOTE_PORT=your-port
401
432
  REMOTE_USER=your-user
@@ -57,6 +57,20 @@
57
57
  - operator identity policy / guard CLI를 수정했으면:
58
58
  - `node scripts/check_operator_guard.mjs`
59
59
  - `node scripts/check_sk_cli_smoke.mjs`
60
+ - deploy actor gate / 배포 script preflight를 수정했으면:
61
+ - `node scripts/check_deploy_actor_guard.mjs`
62
+ - `node scripts/check_operator_guard.mjs`
63
+ - `node scripts/check_sk_cli_smoke.mjs`
64
+ - GitHub Organization canonical URL, NON_OWNER private fork, remote topology, PR handoff 규칙을 수정했으면:
65
+ - `node scripts/check_fork_contribution.mjs`
66
+ - `node scripts/check_work_start_preflight.mjs`
67
+ - `node scripts/check_operator_guard.mjs`
68
+ - `node scripts/check_docs_integrity.mjs README.MD AGENTS.md docs skills`
69
+ - `$sk-git` secret hard-fail 또는 `sk guard secrets`를 수정했으면:
70
+ - `node scripts/check_git_stage_scope_smoke.mjs`
71
+ - `node scripts/check_git_secret_guard_smoke.mjs`
72
+ - `node scripts/check_sk_cli_smoke.mjs`
73
+ - `node scripts/check_docs_integrity.mjs skills/sk-git docs/policies/core-safety.md`
60
74
  - `seokang-skill`의 npm 배포 범위나 bootstrap runtime을 수정했으면:
61
75
  - `node scripts/check_npm_release_scope.mjs --json`
62
76
  - `node scripts/check_npm_release_scope_smoke.mjs`
@@ -18,6 +18,47 @@
18
18
  - 문서가 많더라도 인덱스/개요 -> 관련 상세 순서로 좁혀 읽는다.
19
19
  - 로컬 문서가 비어 있으면 `로컬 프로젝트 문서 부족`을 명시하고 git history + 현재 구조 확인으로 보완한다.
20
20
 
21
+ ### 1-1. Work Start Git Preflight
22
+
23
+ 작업 전 repository가 `profiles/seokang/operator-access.json`의 `Repository Access Matrix` 중 어디에 속하는지 먼저 확인한다.
24
+
25
+ - `noAccess`: NON_OWNER는 clone/fetch/read/fork/PR을 시도하지 않는다.
26
+ - `readOnly`: NON_OWNER는 읽기 분석만 가능하며 branch 생성·fork·PR로 이동하지 않는다.
27
+ - `forkPr`: 아래 NON_OWNER private-fork 시작 순서를 적용한다.
28
+
29
+ - 새 스레드의 첫 product 작업이거나 이전 작업과 다른 요청을 시작하면 코드 분석/수정 전에 아래를 실행한다.
30
+ - `git status --porcelain=v2 --branch`
31
+ - `git branch --show-current`
32
+ - `git remote -v`
33
+ - `sk identity status --json`
34
+ - remote URL에서 repository name을 확인하고 원본이 `selink-lab/<repo>`인지 검증한다. remote, GitHub actor, repository name을 확인할 수 없으면 자동 동기화하지 않는다.
35
+ - 원본 default branch는 hardcode하지 않고 아래처럼 조회한다.
36
+ - `gh repo view selink-lab/<repo> --json defaultBranchRef --jq '.defaultBranchRef.name'`
37
+ - dirty worktree, detached HEAD, 진행 중인 merge/rebase가 있으면 branch switch나 fast-forward merge를 실행하지 않고 현재 상태를 먼저 보고한다.
38
+ - merge: `git rev-parse -q --verify MERGE_HEAD`
39
+ - rebase: `git rev-parse --git-path rebase-merge`, `git rev-parse --git-path rebase-apply`로 경로를 구한 뒤 directory 존재 확인
40
+
41
+ #### OWNER 시작 순서
42
+
43
+ 1. `origin=github.com/selink-lab/<repo>`이고 확인한 repository name과 일치하는지 먼저 검증한다. 개인 fork나 다른 host의 origin이면 fetch/merge하지 않는다.
44
+ 2. 새 작업 전에 원본의 열린 PR을 최대 100건 조회한다.
45
+ - `gh pr list --repo selink-lab/<repo> --state open --limit 100 --json number,title,author,headRefName,baseRefName,url,reviewDecision`
46
+ 3. 열린 PR이 현재 요청과 같은 파일/도메인에 영향을 줄 수 있으면 PR diff와 checks를 먼저 읽고 새 작업과의 충돌 여부를 보고한다. 자동 merge/close는 하지 않는다.
47
+ 4. worktree가 clean하고 현재 branch가 원본 default branch일 때만 `git fetch origin --prune` 후 `git merge --ff-only origin/<default-branch>`로 동기화한다.
48
+ 5. merge 뒤 `git rev-list --left-right --count HEAD...origin/<default-branch>`가 정확히 `0 0`인지 확인한다. local default가 ahead/diverged면 reset/rebase하지 않고 중단한다.
49
+ 6. 다른 작업 branch에 있으면 원격 fetch와 비교까지만 수행하고 임의로 branch를 전환하지 않는다.
50
+
51
+ #### NON_OWNER 시작 순서
52
+
53
+ 1. `origin=github.com/<authenticated-login>/<repo>`, `upstream=github.com/selink-lab/<repo>` private-fork topology를 확인한다.
54
+ 2. 현재 branch의 PR을 `gh pr list --repo selink-lab/<repo> --state all --limit 100 --head <login>:<current-branch> --json number,state,mergedAt,url,baseRefName`으로 확인한다. OPEN이면 기존 PR을 보고하고, CLOSED/MERGED 이력이 있으면 반드시 새 branch를 사용한다.
55
+ 3. worktree가 clean할 때 `git fetch upstream --prune` → `git switch <default-branch>` → `git merge --ff-only upstream/<default-branch>` 순서로 원본 최신 코드를 로컬에 반영한다.
56
+ 4. merge 뒤 `git rev-list --left-right --count HEAD...upstream/<default-branch>`가 정확히 `0 0`인지 확인한다. local default가 ahead/diverged면 reset/rebase하지 않고 중단한다.
57
+ 5. 동기화된 default branch에서 허용 prefix의 새 작업 branch를 만든다. NON_OWNER는 fork의 default branch나 upstream에 push하지 않는다.
58
+ 6. fast-forward가 불가능하거나 conflict가 예상되면 merge commit, rebase, force push로 임의 해결하지 않고 OWNER에게 전달한다.
59
+
60
+ - network/API 오류를 최신 상태로 간주하지 않는다. fetch/PR 조회가 실패하면 실패 범위와 남은 위험을 밝힌다.
61
+
21
62
  ## 2. Track Mapping
22
63
 
23
64
  | 식별자 | Track |
@@ -105,7 +105,48 @@
105
105
  - `sk-deploy`: DB 영향 artifact 또는 영향 미확인 server 배포 전
106
106
  - owner 판정은 DB schema/data 직접 변경 권한을 뜻하지 않는다. 이 문서의 DB Safe-Read 제한은 그대로 유지한다.
107
107
  - 이 gate는 협조적인 사용자의 실수 방지층이다. 로컬 파일/실행 경로를 바꿀 수 있는 사용자를 막는 보안 경계로 간주하지 않는다.
108
- - 실제 보호는 비소유자 DB write credential 미지급, 보호 브랜치/CODEOWNERS, 보호된 CI environment 승인을 함께 사용한다.
108
+ - 실제 보호는 비소유자 DB write credential 미지급, 원본 저장소 Read 권한, private fork/PR, 보호된 CI environment 승인을 함께 사용한다.
109
+
110
+ ## 8-1. Git / Deploy Actor Capability Gate
111
+
112
+ - Git write와 배포는 `profiles/seokang/operator-access.json`의 같은 numeric GitHub user ID 판정을 사용한다.
113
+ - actor 상태별 기본 권한은 아래로 고정한다.
114
+ - `OWNER`: `main`/`master` write, tag/release, production 배포, npm publish, rollback 허용
115
+ - `NON_OWNER`: 개인 private fork의 이름이 확인된 작업 branch push와 원본 저장소 PR까지만 허용. 모든 배포 mutation은 차단
116
+ - `UNKNOWN`: Git write와 모든 배포 mutation 차단
117
+ - Git write 전에는 현재 branch를 확인하고 아래를 실행한다.
118
+ - `sk guard git --action push --branch <current-branch> --repo <repo>`
119
+ - tag/release 전에는 같은 명령의 `--action tag` 또는 `--action release`를 별도로 통과한다.
120
+ - `NON_OWNER`는 원본 `selink-lab` 저장소에 직접 add/commit/push하지 않는다. 개인 private fork의 `origin`에 작업 branch를 push하고 `upstream` 원본으로 PR을 전달하며 merge는 OWNER가 담당한다.
121
+ - NON_OWNER remote topology는 `origin=github.com/<authenticated-login>/<repo>`, `upstream=github.com/selink-lab/<repo>`로 고정한다. host/owner/repository/fork parent 확인이 실패하면 push하지 않는다.
122
+ - GitHub Free private 저장소에서는 branch ruleset이 실제 차단 경계가 아니다. 원본 저장소의 NON_OWNER 권한을 Read로 유지하고 production SSH/npm/DB/API/CDN credential을 제공하지 않는 것이 실제 보호 경계다.
123
+ - Organization에서 private repository forking을 허용하되 fork PR Actions에는 write token, Actions secrets, variables를 전달하지 않는다. fork PR workflow는 OWNER 승인 후에만 실행한다.
124
+ - 조직 전체 2FA 강제는 모든 active member가 2FA를 활성화한 것을 확인한 뒤에만 켠다. 미활성 member가 있는 상태에서는 접근 상실을 막기 위해 강제하지 않는다.
125
+ - 배포는 build, credential 확인, upload, restart, publish보다 먼저 아래를 실행한다.
126
+ - `sk guard deploy --environment <name> --artifact <frontend|server|npm> --action <deploy|rollback> --db-impact-status <none|yes|unknown>`
127
+ - local/preview/staging/production, frontend/server/npm, deploy/rollback을 포함한 모든 배포 mutation은 DB 영향 유무와 관계없이 OWNER 전용이다. NON_OWNER는 로컬 build/test까지만 수행할 수 있다.
128
+ - `NON_OWNER` 작업 branch는 `codex/`, `feature/`, `fix/` 등 policy에 고정된 작업 prefix만 허용한다. develop/release/production/gh-pages/ref-qualified 이름은 허용하지 않는다.
129
+ - DB impact가 `yes` 또는 `unknown`이면 deploy capability gate와 별도로 `sk guard implementation --db-impact`도 통과해야 한다.
130
+ - 로컬 guard는 직접 `git`, `ssh`, `npm` 명령이나 파일 수정으로 우회할 수 있는 협조적 안전장치다. 실제 보호는 upstream Read 권한, private fork/PR, OWNER만 보유한 배포 credential, 보호된 production CI 승인으로 구성한다.
131
+
132
+ ### Repository Access Matrix
133
+
134
+ - NON_OWNER repository 범위의 source of truth는 `profiles/seokang/operator-access.json`의 `access.repositories`다.
135
+ - `km-admin`, `km-admin-api`, `km-admin-app`, `km_bed_selector`: `noAccess`. Organization/team Read와 private fork를 모두 허용하지 않는다.
136
+ - `seokang-codex-setting`: `readOnly`. 설치·업데이트 참고용 Read만 허용하고 private fork/PR은 허용하지 않는다.
137
+ - `price-advisor-spinks`, `price-advisor-sealy`, `slk-office-web`, `slk-api`: `forkPr`. upstream Read + 개인 private fork 작업 branch + 원본 PR만 허용한다.
138
+ - SeoKang OWNER는 `fork-contributors` team에 넣지 않는다. Organization owner 권한과 contributor team 권한을 섞지 않는다.
139
+ - 2FA Organization 강제는 이번 운영 단계에서 보류하며, 추후 모든 active member의 활성화 확인 뒤 별도 적용한다.
140
+
141
+ ## 8-2. Git Secret Hard-Fail
142
+
143
+ - `$sk-git`은 stage 전 `sk guard secrets --worktree`, commit 전 `sk guard secrets --staged`, push 전 `sk guard secrets --outbound --remote origin`을 모두 통과해야 한다.
144
+ - 새 민감 파일명과 고신뢰 secret signature 또는 literal secret assignment가 탐지되면 사용자 확인으로 우회하지 않고 add/commit/push를 중단한다.
145
+ - 출력에는 파일 경로와 rule name만 남기고 탐지된 값이나 줄 원문을 노출하지 않는다.
146
+ - guard는 사용자 로컬 파일을 삭제하거나 자동 수정하지 않는다. staged 검사에서 막힌 경로만 선택적으로 unstage할 수 있다.
147
+ - `.env.example` 같은 placeholder template과 이미 추적 중인 공개 버전 필드 수정은 허용하되, 실제 token signature가 들어가면 차단한다.
148
+ - add 전 `sk guard stage pre-add <confirmed-paths>`, commit 직전 `sk guard stage pre-commit <confirmed-paths>`로 intended commit path set과 Git index를 비교해 unrelated index 혼입을 차단한다.
149
+ - 이 guard는 협조적인 로컬 안전장치이며 GitHub ACL과 credential 분리를 대신하지 않는다. outbound 검사는 push 직전 마지막 fail-closed 단계다.
109
150
 
110
151
  ## 9. Runtime Delegation
111
152
 
@@ -9,6 +9,10 @@
9
9
 
10
10
  - `sk-cli-guide.md`
11
11
  - `sk setup`, `sk sync-agents`, `sk init`, `sk check`, `sk status` 사용 흐름
12
+ - `fork-contributor-guide.md`
13
+ - GitHub Free에서 NON_OWNER가 개인 private fork와 PR로 안전하게 개발하는 순서
14
+ - `github-free-collaboration.md`
15
+ - Organization, team, private fork, Actions, 2FA 운영 기준
12
16
  - `code-style-profile.md`
13
17
  - `sk create`, `sk style`, `sk update`와 starter/profile 적용 기준
14
18
  - `sk-setup-architecture.md`
@@ -0,0 +1,160 @@
1
+ # 친구 계정 Private Fork 개발 가이드
2
+
3
+ ## 목적
4
+
5
+ - GitHub Free를 유지하면서 NON_OWNER가 `selink-lab` 원본 저장소를 직접 수정하지 않게 한다.
6
+ - 친구는 개인 private fork에서 작업 브랜치를 push하고 원본 저장소로 Pull Request만 보낸다.
7
+ - `main` 병합, 모든 배포, tag/release, npm publish, rollback, DB 영향 구현은 SeoKang이 맡는다.
8
+
9
+ ## 1. 최초 계정 준비
10
+
11
+ GitHub CLI와 SeoKang 스킬을 설치한다. Organization 2FA 강제는 현재 보류 상태이며, 2FA 활성화는 추후 별도 운영 단계에서 진행한다.
12
+
13
+ ### macOS
14
+
15
+ ```bash
16
+ brew install gh
17
+ gh auth login
18
+ npm install -g seokang-sk@latest
19
+ sk setup --skip-notion
20
+ ```
21
+
22
+ ### Windows Git Bash
23
+
24
+ ```bash
25
+ winget install --id GitHub.cli
26
+ gh auth login
27
+ npm install -g seokang-sk@latest
28
+ sk setup --skip-notion
29
+ ```
30
+
31
+ 설치 후 실제 로그인 계정과 권한을 확인한다.
32
+
33
+ ```bash
34
+ sk identity status
35
+ sk check
36
+ ```
37
+
38
+ 친구 계정은 `NON_OWNER`가 정상이다. `UNKNOWN`이면 개발을 시작하지 말고 `gh auth login`을 다시 확인한다.
39
+
40
+ ## 2. 작업 가능한 저장소 확인
41
+
42
+ 친구 계정의 repository 범위는 아래로 고정한다.
43
+
44
+ | 구분 | Repository | 가능한 작업 |
45
+ | --- | --- | --- |
46
+ | 접근 없음 | `km-admin`, `km-admin-api`, `km-admin-app`, `km_bed_selector` | 읽기·fork·PR 모두 불가 |
47
+ | Read 전용 | `seokang-codex-setting` | 읽기만 가능, fork/PR 불가 |
48
+ | fork/PR | `price-advisor-spinks`, `price-advisor-sealy`, `slk-office-web`, `slk-api` | 개인 private fork 작업과 원본 PR 가능 |
49
+
50
+ ## 3. 허용된 원본 저장소를 개인 계정으로 fork
51
+
52
+ GitHub의 `selink-lab/<repo>` 화면에서 **Fork**를 눌러 친구 개인 계정 아래 private fork를 만든다. fork를 만든 뒤 아래처럼 clone한다.
53
+
54
+ ```bash
55
+ gh repo clone <friend-login>/<repo>
56
+ cd <repo>
57
+ git remote add upstream https://github.com/selink-lab/<repo>.git
58
+ git remote -v
59
+ ```
60
+
61
+ 원격 저장소는 반드시 아래 구조여야 한다.
62
+
63
+ ```text
64
+ origin https://github.com/<friend-login>/<repo>.git
65
+ upstream https://github.com/selink-lab/<repo>.git
66
+ ```
67
+
68
+ - `origin`: 친구가 push하는 개인 fork
69
+ - `upstream`: 읽기만 하는 `selink-lab` 원본
70
+
71
+ ## 4. 작업 시작 전 원본 동기화
72
+
73
+ 친구는 fork의 default branch를 push하지 않는다. 먼저 원본의 실제 default branch를 확인하고 로컬 branch만 fast-forward한 뒤 작업 브랜치를 만든다.
74
+
75
+ ```bash
76
+ gh repo view selink-lab/<repo> --json defaultBranchRef --jq '.defaultBranchRef.name'
77
+ git switch <default-branch>
78
+ git fetch upstream
79
+ git merge --ff-only upstream/<default-branch>
80
+ git rev-list --left-right --count HEAD...upstream/<default-branch>
81
+ git switch -c feature/<작업명>
82
+ ```
83
+
84
+ `rev-list` 결과는 정확히 `0 0`이어야 한다. local default가 ahead/diverged면 기존 commit을 새 branch에 섞지 말고 중단한다.
85
+
86
+ 작업 브랜치는 `codex/`, `feature/`, `feat/`, `fix/`, `bugfix/`, `chore/`, `docs/`, `refactor/`, `test/` 중 하나로 시작한다.
87
+
88
+ Codex의 새 스레드에서 `$sk-feature` 또는 `$sk-bugfix`를 시작하면 위 preflight를 먼저 수행한다. worktree가 dirty하거나 fast-forward가 불가능하면 자동 동기화하지 않고 친구에게 상태를 보고해야 한다.
89
+
90
+ ## 5. Codex에서 스킬 사용
91
+
92
+ 프로젝트를 Codex에서 열고 아래 순서로 요청한다.
93
+
94
+ ```text
95
+ $sk-plan 구현할 기능을 계획해줘
96
+ $sk-feature 계획한 기능을 구현해줘
97
+ $sk-bugfix 문제가 발생한 부분을 고쳐줘
98
+ $sk-git
99
+ ```
100
+
101
+ DB 영향 구현은 친구 계정에서 차단된다. DB 변경이 필요해 보이면 구현하지 말고 계획과 영향 범위만 SeoKang에게 전달한다.
102
+ `$sk-deploy`는 environment와 무관하게 차단되므로 배포 요청은 SeoKang에게 전달한다.
103
+
104
+ `$sk-git`은 아래를 확인해야 한다.
105
+
106
+ - GitHub actor가 `NON_OWNER`
107
+ - 현재 branch가 허용된 작업 prefix
108
+ - `origin`이 친구 개인 fork
109
+ - `upstream`이 `selink-lab` 원본
110
+ - push 대상이 `origin HEAD:<current-branch>`
111
+ - 같은 branch의 OPEN/CLOSED/MERGED PR 이력
112
+
113
+ 조건을 통과하면 `$sk-git`은 commit/push 뒤 OPEN PR URL을 반환하거나, PR 이력이 없을 때 제목과 본문을 자동 생성해 `selink-lab` 원본 PR까지 만든다. CLOSED/MERGED PR branch는 재사용하지 않고 새 branch를 요구한다.
114
+
115
+ `$sk-git`은 add 전에 worktree, commit 전에 staged index, push 전에 outbound commit history를 각각 검사한다. 새 `.env*`, deploy local config, private key/keystore/credential 파일 또는 고신뢰 token이 탐지되면 확인 없이 hard-fail하며 push하지 않는다. 탐지된 값은 출력하지 않고 로컬 파일도 삭제하지 않는다. 기존 staged path도 intended commit path와 다르면 commit하지 않는다.
116
+
117
+ ## 6. 원본 저장소로 PR 생성
118
+
119
+ 작업 branch push 후 원본 저장소에 PR을 만든다.
120
+
121
+ ```bash
122
+ gh pr create \
123
+ --repo selink-lab/<repo> \
124
+ --base <default-branch> \
125
+ --head <friend-login>:<current-branch> \
126
+ --title "<작업 제목>" \
127
+ --body "<변경 요약과 테스트 결과>"
128
+ ```
129
+
130
+ 친구는 PR 작성까지만 수행한다. merge, tag, release, local/preview/staging/production 배포는 하지 않는다.
131
+
132
+ ## 7. 다음 작업에서 fork 동기화
133
+
134
+ ```bash
135
+ git switch <default-branch>
136
+ git fetch upstream
137
+ git merge --ff-only upstream/<default-branch>
138
+ git rev-list --left-right --count HEAD...upstream/<default-branch>
139
+ git switch -c feature/<다음-작업명>
140
+ ```
141
+
142
+ 충돌이 있으면 `main`에 임의 merge commit을 만들거나 force push하지 말고 SeoKang에게 전달한다.
143
+
144
+ ## 8. 허용/차단 기준
145
+
146
+ | 작업 | 친구 계정 |
147
+ | --- | --- |
148
+ | `fork/PR` 원본 저장소 clone/fetch | 허용 |
149
+ | `fork/PR` 개인 fork 작업 branch push | 허용 |
150
+ | `fork/PR` 원본으로 PR 생성 | 허용 |
151
+ | `Read 전용` 저장소 분석 | 허용 |
152
+ | `접근 없음` 저장소 clone/fetch | GitHub 권한으로 차단 |
153
+ | 원본 main/feature branch 직접 push | GitHub Read 권한으로 차단 |
154
+ | DB 영향 구현 | 스킬 actor gate로 차단 |
155
+ | local/preview/staging/production 배포 | 스킬 actor gate와 credential 미지급으로 차단 |
156
+ | npm/tag/release/rollback | 스킬 actor gate와 credential 분리로 차단 |
157
+
158
+ ## 9. 계정 또는 접근 제거 시
159
+
160
+ Organization/팀 접근을 제거하면 GitHub가 private fork를 삭제할 수 있다. 필요한 미병합 작업은 먼저 PR로 전달하고, 로컬 clone에만 중요한 작업을 남겨두지 않는다.
@@ -0,0 +1,79 @@
1
+ # selink-lab GitHub Free 협업 설정
2
+
3
+ ## 운영 모델
4
+
5
+ - GitHub Organization은 `selink-lab`을 canonical owner로 사용한다.
6
+ - GitHub Team 요금제로 업그레이드하지 않고 Organization의 무료 team 기능을 사용한다.
7
+ - 친구는 `fork-contributors` team을 통해 승인된 원본 private repository만 Read로 본다.
8
+ - fork/PR 대상으로 승인된 repository에서만 개인 private fork에 작업 branch를 push하고 원본으로 PR을 만든다.
9
+ - SeoKang만 merge, 모든 배포, tag/release, npm publish, rollback을 수행한다.
10
+
11
+ ## Organization 설정
12
+
13
+ ### Member privileges
14
+
15
+ - Base permissions: `None`
16
+ - Member repository creation: 비활성화 (`members_can_create_repositories=false`, public/private 모두 차단)
17
+ - Allow forking of private repositories: 활성화
18
+
19
+ ### Team
20
+
21
+ - Team: `fork-contributors`
22
+ - Member: `91kwangmin`만 유지. SeoKang OWNER는 이 team에 넣지 않음
23
+ - Repository role: 아래 표의 Read 대상만 `pull`
24
+ - 신규 repository는 자동 포함하지 않으며 `noAccess`, `readOnly`, `forkPr` 중 하나를 OWNER가 먼저 결정
25
+
26
+ ### Repository access matrix
27
+
28
+ | 구분 | Repository | Team 권한 | Private fork | 친구 작업 |
29
+ | --- | --- | --- | --- | --- |
30
+ | `noAccess` | `km-admin`, `km-admin-api`, `km-admin-app`, `km_bed_selector` | 없음 | 차단 | 읽기·fork·PR 모두 하지 않음 |
31
+ | `readOnly` | `seokang-codex-setting` | Read | 차단 | 설치/업데이트 참고만 가능 |
32
+ | `forkPr` | `price-advisor-spinks`, `price-advisor-sealy`, `slk-office-web`, `slk-api` | Read | 허용 | 개인 private fork → 작업 branch → 원본 PR |
33
+
34
+ source of truth는 `profiles/seokang/operator-access.json`의 `access.repositories`다.
35
+
36
+ ### Actions
37
+
38
+ - Fork pull request workflow를 사용할 때 token 기본 권한은 read-only로 유지
39
+ - Actions가 PR을 생성하거나 승인하는 권한은 비활성화
40
+ - Fork PR에 write token, Actions secrets, variables를 전달하지 않음
41
+ - Fork PR workflow 실행은 OWNER가 검토하고 승인
42
+ - `pull_request_target` 또는 `workflow_run`에서 fork code를 checkout한 뒤 secret을 사용하는 workflow는 금지
43
+
44
+ ### 2FA
45
+
46
+ - 모든 active member가 2FA를 켠 것을 확인하기 전에는 Organization 2FA 강제를 활성화하지 않는다.
47
+ - 미활성 member가 있는 상태에서 강제하면 접근을 잃을 수 있다.
48
+ - 이번 단계에서는 강제 설정을 보류한다. 추후 별도 작업에서 모든 active member 활성화를 확인한 뒤 적용한다.
49
+
50
+ ## 실제 보안 경계
51
+
52
+ GitHub Free private repository에는 branch ruleset을 강제할 수 없으므로 아래가 실제 보호 경계다.
53
+
54
+ - 원본 upstream repository의 친구 권한은 Read (`upstream Read`)
55
+ - 친구 push 대상은 개인 private fork뿐
56
+ - 원본 반영은 PR과 OWNER merge만 사용
57
+ - DB write 및 SSH/npm/API/CDN/production credential은 친구에게 제공하지 않음
58
+ - 모든 배포 mutation은 `sk guard deploy`에서도 OWNER 전용
59
+
60
+ 로컬 skill guard는 실수 방지층이며 GitHub 권한과 credential 분리를 대신하지 않는다.
61
+
62
+ ## 신규 repository 체크리스트
63
+
64
+ 1. repository owner가 `selink-lab`인지 확인
65
+ 2. `noAccess`, `readOnly`, `forkPr` 중 운영 모드를 먼저 결정
66
+ 3. `forkPr`면 team Read + repository-level `Allow forking`을 활성화
67
+ 4. `readOnly`면 team Read만 추가하고 repository-level `Allow forking`은 비활성화
68
+ 5. `noAccess`면 team에 추가하지 않고 repository-level `Allow forking`도 비활성화
69
+ 6. Actions token 기본 권한이 read-only인지 확인
70
+ 7. 배포 secret/environment 접근자가 OWNER인지 확인
71
+ 8. `forkPr` repository만 친구가 개인 fork를 만들고 `origin=개인 fork`, `upstream=selink-lab 원본`으로 clone
72
+
73
+ 친구의 실제 설치와 작업 순서는 [친구 계정 Private Fork 개발 가이드](./fork-contributor-guide.md)를 따른다.
74
+
75
+ ## 새 작업 시작 역할
76
+
77
+ - SeoKang(OWNER): 원본 저장소의 열린 PR과 diff/checks를 먼저 확인하고 현재 요청과 충돌하는지 판단한 뒤 새 작업을 시작한다.
78
+ - 친구(NON_OWNER): upstream의 실제 default branch를 fetch하고 local default branch를 `--ff-only`로 갱신한 뒤 새 작업 branch를 만든다.
79
+ - 두 계정 모두 dirty worktree, merge/rebase 진행 상태, API/fetch 실패를 무시하고 자동 branch 전환하지 않는다.
@@ -80,7 +80,7 @@ sk setup
80
80
  - `sk setup --configure-notion`으로 사용자별 Notion workspace 위치를 로컬 파일에 분리할 수 있다.
81
81
  - `.sk/project-memory.json`, `.sk/notepad.md`를 통해 다음 세션이 이전 맥락을 먼저 읽을 수 있다.
82
82
  - `sk search`로 예전 Codex transcript를 다시 찾을 수 있다.
83
- - `sk identity status`와 `sk guard implementation --db-impact`로 DB 영향 구현을 owner에게만 허용할 수 있다.
83
+ - `sk identity status`와 `sk guard`로 DB 영향 구현, Git write, 배포 권한을 owner/non-owner 기준으로 제한하고 Git secret을 commit 전에 차단할 수 있다.
84
84
 
85
85
  ## 3. 처음 한 번만 해야 하는 것
86
86
 
@@ -264,7 +264,7 @@ sk status
264
264
 
265
265
  이 명령은 현재 프로젝트 기준 `.sk` 상태, 메모 파일 존재 여부, 최근 backup을 보여준다.
266
266
 
267
- ### 4-5. DB 영향 구현 owner 확인
267
+ ### 4-5. Operator 권한 확인
268
268
 
269
269
  DB 영향 구현은 GitHub CLI로 `github.com`에 실제 로그인된 사용자의 숫자형 user ID를 조회해 판정한다. Codex 로그인 방식, `git config`의 name/email, remote owner, OS 사용자명은 권한 근거로 사용하지 않는다. GitHub Enterprise나 `GH_HOST` 기본값은 owner 판정에 사용하지 않는다.
270
270
 
@@ -285,7 +285,50 @@ sk guard implementation --db-impact
285
285
  - `NON_OWNER`: 구현 차단
286
286
  - `UNKNOWN`: GitHub CLI 부재, 미인증, 네트워크/API 오류, 정책 오류를 포함하며 구현 차단
287
287
 
288
- 차단 상태에서도 planning, read-only 코드 분석, DB safe-read는 가능하다. 이 로컬 guard는 실수 방지층이므로 실제 보호에는 DB write credential 분리와 GitHub 보호 브랜치/CODEOWNERS/보호된 CI 승인을 함께 사용한다.
288
+ Git write는 현재 branch와 action을 함께 검사한다.
289
+
290
+ ```bash
291
+ sk guard git --action push --branch codex/my-feature --repo price-advisor-spinks
292
+ sk guard git --action tag --branch main --repo seokang-codex-setting
293
+ ```
294
+
295
+ - NON_OWNER는 이름이 확인된 작업 branch를 개인 private fork의 `origin`에 push하고 `selink-lab` 원본 `upstream`으로 PR을 만드는 것까지만 허용된다.
296
+
297
+ Git add 전과 commit 전에는 아래 두 검사를 순서대로 실행한다.
298
+
299
+ ```bash
300
+ sk guard secrets --worktree
301
+ sk guard stage pre-add <confirmed-paths>
302
+ git add -- <confirmed-paths>
303
+ sk guard secrets --staged
304
+ sk guard stage pre-commit <confirmed-paths>
305
+ git commit -m "<message>"
306
+ sk guard secrets --outbound --remote origin
307
+ ```
308
+
309
+ 새 `.env*`, deploy local config, private key/credential 파일, 고신뢰 token 또는 outbound commit history의 secret이 탐지되면 종료 코드 `2`로 hard-fail한다. 출력에는 redaction된 파일과 rule name만 남기며 로컬 파일은 삭제하지 않는다.
310
+ - main/master write, tag, release는 OWNER 전용이다.
311
+ - UNKNOWN은 feature branch를 포함한 모든 Git write가 차단된다.
312
+
313
+ 친구 계정의 최초 설치, remote 구성, Codex 스킬 사용, PR 생성 절차는 [친구 계정 Private Fork 개발 가이드](./fork-contributor-guide.md)를 따른다.
314
+
315
+ 배포는 environment, artifact, action, DB impact를 함께 검사한다.
316
+
317
+ ```bash
318
+ sk guard deploy \
319
+ --environment staging \
320
+ --artifact frontend \
321
+ --action deploy \
322
+ --isolated \
323
+ --isolation-evidence ci-environment:staging \
324
+ --db-impact-status none
325
+ ```
326
+
327
+ - NON_OWNER는 local/preview/staging을 포함한 모든 배포 mutation이 차단된다. 로컬 build/test만 허용된다.
328
+ - production, npm publish, rollback을 포함한 모든 배포는 OWNER 전용이다.
329
+ - `yes`/`unknown` DB impact는 별도로 `sk guard implementation --db-impact`도 통과해야 한다.
330
+
331
+ 차단 상태에서도 planning, read-only 코드 분석, DB safe-read는 가능하다. 이 로컬 guard는 실수 방지층이므로 실제 보호에는 원본 저장소 Read 권한, 개인 private fork/PR, DB write 및 모든 배포 credential 미지급을 함께 사용한다.
289
332
 
290
333
  ### 4-6. DB safe-read alias 맞추기
291
334
 
@@ -488,4 +531,4 @@ Codex에서 같은 흐름을 실행하려면 `$seokang-update`를 사용한다.
488
531
  - `sk check` = 설치 결과 점검
489
532
  - `sk status` = 지금 상태 확인
490
533
  - `sk memory show`, `sk search` = 이전 맥락 복원
491
- - `npm run check:harness` = defaults / DDL / docs / GPT-5.6 model routing / UI router / automation / CLI smoke 전체 검증
534
+ - `npm run check:harness` = defaults / DDL / docs / GPT-5.6 model routing / UI router / automation / operator/deploy guard / npm release / CLI smoke 전체 검증
@@ -33,5 +33,6 @@
33
33
 
34
34
  - DB impact 결론 (`있음` | `없음` | `미확인`):
35
35
  - Actor gate 실행 여부와 결과:
36
+ - Git/deploy capability gate 적용 시점:
36
37
  - 실행할 deterministic checks:
37
38
  - 해당 없음으로 닫는 checks:
@@ -26,6 +26,7 @@
26
26
  ### DB impact (`있음` | `없음` | `미확인`)
27
27
  ### Actor gate (`해당 없음` | `ALLOW` | `DENY`)
28
28
  ### Actor gate evidence (`sk guard implementation --db-impact` 실행 결과 또는 생략 근거)
29
+ ### Git/deploy gate (`해당 없음` | `Git write 시 sk-git에서 실행` | `배포 시 sk-deploy에서 실행`)
29
30
 
30
31
  ## 4. 검증 계획
31
32
 
@@ -42,6 +43,7 @@
42
43
  | `check_ddl_comments.mjs` | | | |
43
44
  | `check_docs_integrity.mjs` | | | |
44
45
  | `check_operator_guard.mjs` | | | |
46
+ | `check_deploy_actor_guard.mjs` | | | |
45
47
  | `check_sk_cli_smoke.mjs` | | | |
46
48
 
47
49
  ## 6. 완료 기준
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "seokang-sk",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "SeoKang Codex 공용 설정과 스킬을 설치하는 CLI",
5
5
  "license": "MIT",
6
- "homepage": "https://github.com/Seokang/seokang-codex-setting",
6
+ "homepage": "https://github.com/selink-lab/seokang-codex-setting",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/Seokang/seokang-codex-setting.git"
9
+ "url": "git+https://github.com/selink-lab/seokang-codex-setting.git"
10
10
  },
11
11
  "bugs": {
12
- "url": "https://github.com/Seokang/seokang-codex-setting/issues"
12
+ "url": "https://github.com/selink-lab/seokang-codex-setting/issues"
13
13
  },
14
14
  "keywords": [
15
15
  "codex",
@@ -22,7 +22,7 @@
22
22
  "sk": "scripts/sk.mjs"
23
23
  },
24
24
  "scripts": {
25
- "check:harness": "npm run check:harness:defaults -- . && npm run check:harness:ddl-comments -- . && npm run check:harness:docs -- . && npm run check:harness:style && npm run check:harness:models && npm run check:harness:ui-router && npm run check:harness:automation && npm run check:harness:operator-guard && npm run check:harness:npm-release && npm run check:harness:cli-smoke",
25
+ "check:harness": "npm run check:harness:defaults -- . && npm run check:harness:ddl-comments -- . && npm run check:harness:docs -- . && npm run check:harness:style && npm run check:harness:models && npm run check:harness:ui-router && npm run check:harness:automation && npm run check:harness:operator-guard && npm run check:harness:deploy-guard && npm run check:harness:fork-workflow && npm run check:harness:work-start && npm run check:harness:git-stage && npm run check:harness:git-secrets && npm run check:harness:npm-release && npm run check:harness:cli-smoke",
26
26
  "check:harness:defaults": "node scripts/check_no_unauthorized_defaults.mjs",
27
27
  "check:harness:ddl-comments": "node scripts/check_ddl_comments.mjs",
28
28
  "check:harness:docs": "node scripts/check_docs_integrity.mjs",
@@ -31,6 +31,11 @@
31
31
  "check:harness:ui-router": "node scripts/check_ui_runtime_router.mjs",
32
32
  "check:harness:automation": "node scripts/check_automation_safety.mjs",
33
33
  "check:harness:operator-guard": "node scripts/check_operator_guard.mjs",
34
+ "check:harness:deploy-guard": "node scripts/check_deploy_actor_guard.mjs",
35
+ "check:harness:fork-workflow": "node scripts/check_fork_contribution.mjs",
36
+ "check:harness:work-start": "node scripts/check_work_start_preflight.mjs",
37
+ "check:harness:git-stage": "node scripts/check_git_stage_scope_smoke.mjs",
38
+ "check:harness:git-secrets": "node scripts/check_git_secret_guard_smoke.mjs",
34
39
  "check:harness:npm-release": "node scripts/check_npm_release_scope_smoke.mjs",
35
40
  "check:harness:cli-smoke": "node scripts/check_sk_cli_smoke.mjs"
36
41
  },
@@ -3,6 +3,49 @@
3
3
  "provider": "github-cli",
4
4
  "githubHost": "github.com",
5
5
  "unknownIdentityBehavior": "deny",
6
+ "access": {
7
+ "git": {
8
+ "ownerOnlyBranches": [
9
+ "main",
10
+ "master"
11
+ ],
12
+ "ownerOnlyActions": [
13
+ "tag",
14
+ "release"
15
+ ],
16
+ "nonOwnerBranchPrefixes": [
17
+ "codex/",
18
+ "feature/",
19
+ "feat/",
20
+ "fix/",
21
+ "bugfix/",
22
+ "chore/",
23
+ "docs/",
24
+ "refactor/",
25
+ "test/"
26
+ ]
27
+ },
28
+ "deploy": {
29
+ "ownerOnly": true
30
+ },
31
+ "repositories": {
32
+ "noAccess": [
33
+ "km-admin",
34
+ "km-admin-api",
35
+ "km-admin-app",
36
+ "km_bed_selector"
37
+ ],
38
+ "readOnly": [
39
+ "seokang-codex-setting"
40
+ ],
41
+ "forkPr": [
42
+ "price-advisor-spinks",
43
+ "price-advisor-sealy",
44
+ "slk-office-web",
45
+ "slk-api"
46
+ ]
47
+ }
48
+ },
6
49
  "owners": [
7
50
  {
8
51
  "githubUserId": 48157145,