infisical-sync-skill
Expert knowledge for the Infisical Sync Hand — Infisical API reference, vault operations, error patterns, security guidance
소스 정보
- 저장소
- RightNow-AI/openfang
- 최근 소스 활동
- 2026년 3월 23일 19:01
- 감지된 SKILL.md 언어
- 영어
- 스타
- 18,210
- 포크
- 2,290
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
파일 탐색기
2 개 파일SKILL.md 표시 중
SKILL.md
소스 지침 · 읽기 전용 미리보기- name
- infisical-sync-skill
- version
- 1.0.0
- description
- Expert knowledge for the Infisical Sync Hand — Infisical API reference, vault operations, error patterns, security guidance
- author
- OpenFang
- tags
- ["secrets","infisical","vault","security","sync"]
- tools
- ["shell_exec","vault_set","vault_get","vault_list","vault_delete","memory_store","memory_recall"]
- runtime
- prompt_only
# Infisical Sync Expert Knowledge
## 1. Infisical API Reference
### Base URL
All requests go to `$INFISICAL_URL`. This is the self-hosted instance base URL, e.g. `https://infisical.example.com`.
### Authentication — Universal Auth
Infisical uses Machine Identities with Universal Auth for agent-to-agent communication.
**Endpoint**: `POST /api/v1/auth/universal-auth/login`
**Request**:
```json
{
"clientId": "<INFISICAL_CLIENT_ID>",
"clientSecret": "<INFISICAL_CLIENT_SECRET>"
}
```
**Response** (success):
```json
{
"accessToken": "eyJ...",
"expiresIn": 7200,
"accessTokenMaxTTL": 43200,
"tokenType": "Bearer"
}
```
**curl example**:
```bash
RESPONSE=$(curl -s -X POST "$INFISICAL_URL/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"$INFISICAL_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CLIENT_SECRET\"}")
ACCESS_TOKEN=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['accessToken'])")
```
Token lifetime: `expiresIn` seconds (usually 7200 = 2 hours). Re-authenticate when expired.
---
### List Secrets
**Endpoint**: `GET /api/v4/secrets`
**Query parameters**:
| Param | Required | Description |
|-------|----------|-------------|
| `projectId` | Yes | Infisical project ID |
| `environment` | Yes | Environment slug (e.g. `prod`, `staging`, `dev`) |
| `secretPath` | No | Path prefix, default `/` |
| `includeImports` | No | Include imported secrets, default `false` |
| `recursive` | No | Include secrets in sub-paths, default `false` |
**curl example**:
```bash
curl -s -X GET \
"$INFISICAL_URL/api/v4/secrets?projectId=$PROJECT_ID&environment=$ENVIRONMENT&secretPath=/" \
-H "Authorization: Bearer $ACCESS_TOKEN"
```
**Response shape**:
```json
{
"secrets": [
{
"id": "uuid",
"version": 1,
"secretKey": "DATABASE_URL",
"secretValue": "postgres://...",
"secretComment": "",
"environment": "prod",
"workspace": "uuid"
}
],
"imports": []
}
```
Parse with:
```bash
echo "$RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for s in data.get('secrets', []):
print(s['secretKey'])
"
```
---
### Create or Update a Secret
The API does **not** provide a single upsert endpoint. `POST` creates only (returns 409 if the secret already exists); `PATCH` updates only (returns 404 if missing). Use the create-then-update pattern:
**Step 1 — Try to create (POST)**
**Endpoint**: `POST /api/v4/secrets/{secretName}`
**Request body**:
```json
{
"projectId": "<PROJECT_ID>",
"environment": "<ENV>",
"secretValue": "<VALUE>",
"secretPath": "/"
}
```
```bash
HTTP_STATUS=$(curl -s -o /tmp/infisical_response.json -w "%{http_code}" \
-X POST "$INFISICAL_URL/api/v4/secrets/$SECRET_NAME" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"projectId\":\"$PROJECT_ID\",\"environment\":\"$ENVIRONMENT\",\"secretValue\":\"$SECRET_VALUE\",\"secretPath\":\"/\"}")
```
Returns `201` on success.
**Step 2 — If 409, update via PATCH**
**Endpoint**: `PATCH /api/v4/secrets/{secretName}`
```bash
if [ "$HTTP_STATUS" = "409" ]; then
HTTP_STATUS=$(curl -s -o /tmp/infisical_response.json -w "%{http_code}" \
-X PATCH "$INFISICAL_URL/api/v4/secrets/$SECRET_NAME" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"projectId\":\"$PROJECT_ID\",\"environment\":\"$ENVIRONMENT\",\"secretValue\":\"$SECRET_VALUE\",\"secretPath\":\"/\"}")
fi
```
Returns `200` on success. Any other status code is an error.
**Important**: URL-encode the secret name if it contains special characters.
---
### Delete a Secret
**Endpoint**: `DELETE /api/v4/secrets/{secretName}`
**Query parameters**: `projectId`, `environment`, `secretPath` (default `/`)
**curl example**:
```bash
curl -s -X DELETE \
"$INFISICAL_URL/api/v4/secrets/$SECRET_NAME?projectId=$PROJECT_ID&environment=$ENVIRONMENT&secretPath=/" \
-H "Authorization: Bearer $ACCESS_TOKEN"
```
---
### List Accessible Projects (Workspaces)
**Endpoint**: `GET /api/v1/workspace`
```bash
curl -s -X GET "$INFISICAL_URL/api/v1/workspace" \
-H "Authorization: Bearer $ACCESS_TOKEN"
```
Response: `{ "workspaces": [{ "id": "uuid", "name": "...", "environments": [...] }] }`
---
## 2. HTTP Error Codes
| Code | Meaning | Action |
|------|---------|--------|
| 200/201 | Success | Continue |
| 400 | Bad Request | Log the response body — likely malformed JSON or missing field |
| 401 | Unauthorized | Re-authenticate; token may have expired |
| 403 | Forbidden | Machine identity lacks permissions — check Infisical Access Control |
| 404 | Not Found | Secret or project doesn't exist |
| 429 | Rate Limited | Wait 60 seconds, retry once |
| 500/503 | Server Error | Log + retry once after 30 seconds; notify if still failing |
Always check HTTP status before trusting response body:
```bash
HTTP_STATUS=$(curl -s -o /tmp/infisical_response.json -w "%{http_code}" ...)
if [ "$HTTP_STATUS" != "200" ] && [ "$HTTP_STATUS" != "201" ]; then
# handle error
fi
RESPONSE=$(cat /tmp/infisical_response.json)
```
---
## 3. Sync State File Format
Stored at `infisical_sync_state.json`:
```json
{
"last_sync": "2025-01-15T10:30:00Z",
"project_ids": ["uuid1", "uuid2"],
"environment": "prod",
"secrets": {
"DATABASE_URL": {
"hash": "sha256_of_key_plus_value",
"version": 3,
"last_synced": "2025-01-15T10:30:00Z"
}
},
"error_count": 0,
"push_count": 12,
"pull_count": 47
}
```
**Hash computation** (to detect changes without storing values):
```bash
echo -n "DATABASE_URL:postgres://..." | sha256sum | awk '{print $1}'
```
Or with Python:
```python
import hashlib
h = hashlib.sha256(f"{key}:{value}".encode()).hexdigest()
```
---
## 4. Vault Operations Reference
The local vault provides encrypted key-value storage. All secrets synced from Infisical go here.
| Operation | Description |
|-----------|-------------|
| `vault_set key=K value=V` | Write or overwrite secret K |
| `vault_get key=K` | Read secret K |
| `vault_list` | List all keys (values not returned) |
| `vault_delete key=K` | Delete secret K |
**Bulk sync pattern**:
```
// Pull from Infisical → vault
for each (key, value) in infisical_secrets:
vault_set key=<key> value=<value>
// Optionally remove orphans
vault_list → local_keys
infisical_keys = set of keys returned by Infisical
for key in local_keys - infisical_keys:
vault_delete key=<key>
```
---
## 5. Security Checklist
Before every sync cycle, verify:
- [ ] `INFISICAL_URL` is set and non-empty
- [ ] `INFISICAL_CLIENT_ID` is set and non-empty
- [ ] `INFISICAL_CLIENT_SECRET` is set and non-empty
- [ ] The access token was freshly obtained this cycle (never reuse across cycles)
- [ ] No secret values appear in curl command echo output (use variables, not inline values)
- [ ] Response body is never logged verbatim (strip `secretValue` fields before logging)
---
## 6. Common Failure Modes
### "Failed to fetch secrets: 403 Forbidden"
The Machine Identity exists but lacks permissions. In Infisical:
1. Go to Access Control → Machine Identities
2. Find this agent's identity
3. Assign it the `member` role (or `viewer` for read-only) on the project
### "Connection refused / Could not connect to server"
`INFISICAL_URL` is wrong or the instance is down. Verify the URL is reachable:
```bash
curl -s "$INFISICAL_URL/api/status" | python3 -c "import sys,json; print(json.load(sys.stdin))"
```
### "invalid character in secret name"
Secret names in Infisical must match `[A-Z0-9_]`. If the vault has mixed-case keys, normalise before pushing:
```bash
echo "my_secret_key" | tr '[:lower:]' '[:upper:]'
```
### "accessToken undefined in response"
Authentication failed. The response body will contain an error message. Check:
1. `INFISICAL_CLIENT_ID` and `INFISICAL_CLIENT_SECRET` are correct
2. The Machine Identity is not disabled in Infisical
3. The Machine Identity's token TTL hasn't been set to 0
---
## 7. Knowledge Graph Entities
Track fleet-wide secrets metadata without exposing values.
### Entity types
- `service` — the Infisical instance itself
- `secret_project` — an Infisical workspace/project
- `secret` — a named secret (key only, never value)
### Relation types
- `secret` → `belongs_to` → `secret_project`
- `secret_project` → `hosted_by` → `service`
- `secret` → `synced_to` → `agent_vault`
### Query examples
```
knowledge_query type=secret // list all known secrets
knowledge_query type=secret_project // list all projects
knowledge_query relation=belongs_to target=<project_id> // secrets in a project
```
GitHub에서 보기