mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-13 23:03:34 +08:00
fix(skills): keep curl credentials out of argv (#2175)
* fix(skills): avoid curl credential argv leaks * test(ci): guard secret curl examples
This commit is contained in:
parent
40673a89fa
commit
70fde3c14f
@ -65,6 +65,15 @@ MCP が利用できない場合は、`curl` またはヘルパースクリプト
|
||||
|
||||
シェル環境変数、シークレットマネージャー、またはリポジトリにコミットしないローカル環境ファイルに保存してください。
|
||||
|
||||
直接 `curl` 例では、Jira ユーザー設定を標準入力で渡し、認証情報がコマンドライン引数に出ないようにします。
|
||||
|
||||
```bash
|
||||
jira_curl() {
|
||||
printf 'user = "%s:%s"\n' "$JIRA_EMAIL" "$JIRA_API_TOKEN" |
|
||||
curl -s -K - "$@"
|
||||
}
|
||||
```
|
||||
|
||||
## MCP ツールリファレンス
|
||||
|
||||
`mcp-atlassian` MCP サーバーが設定されている場合、以下のツールが利用可能です。
|
||||
@ -88,7 +97,7 @@ MCP が利用できない場合は、`curl` またはヘルパースクリプト
|
||||
### チケットの取得
|
||||
|
||||
```bash
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
-H "Content-Type: application/json" \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234" | jq '{
|
||||
key: .key,
|
||||
@ -105,7 +114,7 @@ curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### コメントの取得
|
||||
|
||||
```bash
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
-H "Content-Type: application/json" \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234?fields=comment" | jq '.fields.comment.comments[] | {
|
||||
author: .author.displayName,
|
||||
@ -117,7 +126,7 @@ curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### コメントの追加
|
||||
|
||||
```bash
|
||||
curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"body": {
|
||||
@ -136,11 +145,11 @@ curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
|
||||
```bash
|
||||
# 1. 利用可能なトランジションを取得
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234/transitions" | jq '.transitions[] | {id, name: .name}'
|
||||
|
||||
# 2. トランジションを実行(TRANSITION_ID を置き換える)
|
||||
curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"transition": {"id": "TRANSITION_ID"}}' \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234/transitions"
|
||||
@ -149,7 +158,7 @@ curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### JQL での検索
|
||||
|
||||
```bash
|
||||
curl -s -G -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -G \
|
||||
--data-urlencode "jql=project = PROJ AND status = 'In Progress'" \
|
||||
"$JIRA_URL/rest/api/3/search"
|
||||
```
|
||||
|
||||
@ -67,6 +67,15 @@ origin: ECC
|
||||
|
||||
将这些存储在您的 shell 环境、密钥管理器或未跟踪的本地环境文件中。不要将其提交到仓库。
|
||||
|
||||
对于直接 `curl` 示例,请通过标准输入传递 Jira 用户配置,避免凭据出现在命令行参数中。
|
||||
|
||||
```bash
|
||||
jira_curl() {
|
||||
printf 'user = "%s:%s"\n' "$JIRA_EMAIL" "$JIRA_API_TOKEN" |
|
||||
curl -s -K - "$@"
|
||||
}
|
||||
```
|
||||
|
||||
## MCP 工具参考
|
||||
|
||||
当配置了 `mcp-atlassian` MCP 服务器时,以下工具可用:
|
||||
@ -90,7 +99,7 @@ origin: ECC
|
||||
### 获取工单
|
||||
|
||||
```bash
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
-H "Content-Type: application/json" \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234" | jq '{
|
||||
key: .key,
|
||||
@ -107,7 +116,7 @@ curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### 获取评论
|
||||
|
||||
```bash
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
-H "Content-Type: application/json" \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234?fields=comment" | jq '.fields.comment.comments[] | {
|
||||
author: .author.displayName,
|
||||
@ -119,7 +128,7 @@ curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### 添加评论
|
||||
|
||||
```bash
|
||||
curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"body": {
|
||||
@ -138,11 +147,11 @@ curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
|
||||
```bash
|
||||
# 1. Get available transitions
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234/transitions" | jq '.transitions[] | {id, name: .name}'
|
||||
|
||||
# 2. Execute transition (replace TRANSITION_ID)
|
||||
curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"transition": {"id": "TRANSITION_ID"}}' \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234/transitions"
|
||||
@ -151,7 +160,7 @@ curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### 使用 JQL 搜索
|
||||
|
||||
```bash
|
||||
curl -s -G -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -G \
|
||||
--data-urlencode "jql=project = PROJ AND status = 'In Progress'" \
|
||||
"$JIRA_URL/rest/api/3/search"
|
||||
```
|
||||
|
||||
@ -65,6 +65,15 @@ If MCP is not available, use the Jira REST API v3 directly via `curl` or a helpe
|
||||
|
||||
Store these in your shell environment, secrets manager, or an untracked local env file. Do not commit them to the repo.
|
||||
|
||||
For direct `curl` examples, keep credentials out of command-line arguments by passing the Jira user config on stdin:
|
||||
|
||||
```bash
|
||||
jira_curl() {
|
||||
printf 'user = "%s:%s"\n' "$JIRA_EMAIL" "$JIRA_API_TOKEN" |
|
||||
curl -s -K - "$@"
|
||||
}
|
||||
```
|
||||
|
||||
## MCP Tools Reference
|
||||
|
||||
When the `mcp-atlassian` MCP server is configured, these tools are available:
|
||||
@ -88,7 +97,7 @@ When the `mcp-atlassian` MCP server is configured, these tools are available:
|
||||
### Fetch a Ticket
|
||||
|
||||
```bash
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
-H "Content-Type: application/json" \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234" | jq '{
|
||||
key: .key,
|
||||
@ -105,7 +114,7 @@ curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### Fetch Comments
|
||||
|
||||
```bash
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
-H "Content-Type: application/json" \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234?fields=comment" | jq '.fields.comment.comments[] | {
|
||||
author: .author.displayName,
|
||||
@ -117,7 +126,7 @@ curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### Add a Comment
|
||||
|
||||
```bash
|
||||
curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"body": {
|
||||
@ -136,11 +145,11 @@ curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
|
||||
```bash
|
||||
# 1. Get available transitions
|
||||
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234/transitions" | jq '.transitions[] | {id, name: .name}'
|
||||
|
||||
# 2. Execute transition (replace TRANSITION_ID)
|
||||
curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"transition": {"id": "TRANSITION_ID"}}' \
|
||||
"$JIRA_URL/rest/api/3/issue/PROJ-1234/transitions"
|
||||
@ -149,7 +158,7 @@ curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
### Search with JQL
|
||||
|
||||
```bash
|
||||
curl -s -G -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
|
||||
jira_curl -G \
|
||||
--data-urlencode "jql=project = PROJ AND status = 'In Progress'" \
|
||||
"$JIRA_URL/rest/api/3/search"
|
||||
```
|
||||
|
||||
@ -23,7 +23,8 @@ Connects Claude Code to [SocialClaw](https://getsocialclaw.com) for agent-driven
|
||||
export SC_API_KEY="<workspace-key>"
|
||||
|
||||
# Verify access
|
||||
curl -sS -H "Authorization: Bearer $SC_API_KEY" https://getsocialclaw.com/v1/keys/validate
|
||||
printf 'header = "Authorization: Bearer %s"\n' "$SC_API_KEY" |
|
||||
curl -sS -K - https://getsocialclaw.com/v1/keys/validate
|
||||
|
||||
# Install CLI (optional but recommended)
|
||||
npm install -g socialclaw@0.1.12
|
||||
|
||||
96
tests/ci/secret-curl-flags.test.js
Normal file
96
tests/ci/secret-curl-flags.test.js
Normal file
@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Guard agent-facing curl examples from exposing credentials in argv.
|
||||
*/
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '..', '..');
|
||||
|
||||
const jiraDocs = [
|
||||
'skills/jira-integration/SKILL.md',
|
||||
'docs/ja-JP/skills/jira-integration/SKILL.md',
|
||||
'docs/zh-CN/skills/jira-integration/SKILL.md',
|
||||
];
|
||||
|
||||
const socialDocs = [
|
||||
'skills/social-publisher/SKILL.md',
|
||||
];
|
||||
|
||||
function test(name, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(` ✓ ${name}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${name}`);
|
||||
console.log(` Error: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
function shellExamples(source) {
|
||||
const examples = [];
|
||||
const fencePattern = /```(?:bash|sh|shell)\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = fencePattern.exec(source)) !== null) {
|
||||
examples.push(match[1].replace(/\\\r?\n\s*/g, ' '));
|
||||
}
|
||||
|
||||
return examples.join('\n');
|
||||
}
|
||||
|
||||
function run() {
|
||||
console.log('\n=== Testing secret-safe curl examples ===\n');
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const relativePath of jiraDocs) {
|
||||
if (test(`${relativePath} keeps Jira credentials out of curl argv`, () => {
|
||||
const source = read(relativePath);
|
||||
const shell = shellExamples(source);
|
||||
|
||||
assert.match(shell, /jira_curl\(\)/, 'Expected a Jira curl wrapper');
|
||||
assert.match(shell, /\bcurl -s -K - "\$@"/, 'Expected curl config stdin in Jira wrapper');
|
||||
assert.doesNotMatch(
|
||||
shell,
|
||||
/\bcurl\b[^\n]*(?:-u|--user)(?:=|\s+)(?:"|')?\$JIRA_EMAIL:\$JIRA_API_TOKEN/,
|
||||
'Jira credentials must not be passed with curl -u/--user',
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
}
|
||||
|
||||
for (const relativePath of socialDocs) {
|
||||
if (test(`${relativePath} keeps SocialClaw bearer token out of curl argv`, () => {
|
||||
const source = read(relativePath);
|
||||
const shell = shellExamples(source);
|
||||
|
||||
assert.match(
|
||||
shell,
|
||||
/printf 'header = "Authorization: Bearer %s"\\n' "\$SC_API_KEY" \|/,
|
||||
'Expected SocialClaw bearer header to be passed via curl config stdin',
|
||||
);
|
||||
assert.match(shell, /\bcurl -sS -K - https:\/\/getsocialclaw\.com\/v1\/keys\/validate/, 'Expected curl -K - validation call');
|
||||
assert.doesNotMatch(
|
||||
shell,
|
||||
/\bcurl\b[^\n]*-H\s+(?:"|')Authorization:\s*Bearer\s+\$SC_API_KEY(?:"|')/,
|
||||
'SocialClaw bearer token must not be passed with curl -H',
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
}
|
||||
|
||||
console.log(`\nPassed: ${passed}`);
|
||||
console.log(`Failed: ${failed}`);
|
||||
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
run();
|
||||
Loading…
x
Reference in New Issue
Block a user