Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ coverage.txt
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

.env
.env.*
!.env.example

# Dependency directories (remove the comment below to include it)
# vendor/

Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 2.19.7
## 新增
1. `qshell sandbox injection-rule create` / `update` 与 `qshell sandbox create --inline-injection` 新增 `github` 注入类型:通过 `--api-key` / `api-key=` 传入 GitHub Token;平台克隆仓库及匹配 `github.com` / `api.github.com` 出站请求时自动注入 token,沙箱内不可见明文
2. `qshell sandbox create` 新增 `--resource` 参数,支持在沙箱启动前由平台拉取 GitHub 仓库快照并挂载到指定路径,格式 `type=github_repository,url=<url>,mount-path=<absPath>,token=<token>`(`type` 可省略,`mount-path` 也可写作 `mount`;同一沙箱内多条 `--resource` 必须共用同一 token)

## 更新
1. 升级 `github.com/qiniu/go-sdk/v7` 到 `v7.26.12`,附带修复其内部 `Commands.Connect` 重复关闭 channel 引发的 panic,并对 `GitRepositoryResource` 必填字段进行 SDK 侧校验

# 2.19.6
## 修复
1. 修复 `qshell sandbox template build` 在 rebuild 场景下清空 `qshell.sandbox.toml` 中 `from_image` / `from_template` 的问题,避免配置了父模板的 Dockerfile 回退到 `FROM scratch` 后构建失败;CLI 显式传入 `--from-image` / `--from-template` 时仍会在 rebuild 场景报错
Expand Down
13 changes: 12 additions & 1 deletion cmd/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,17 @@ var sandboxCreateCmdBuilder = func(cfg *iqshell.Config) *cobra.Command {
--inline-injection 'type=openai,api-key=sk-xxx' \
--inline-injection 'type=http,base-url=https://api.example.com,headers=Authorization=Bearer token;X-Env=prod'
qshell sbx cr my-template \
--inline-injection 'type=openai,api-key=sk-xxx'`,
--inline-injection 'type=openai,api-key=sk-xxx'

# Create with a GitHub credential inline injection (token passed via api-key)
qshell sandbox create my-template --inline-injection 'type=github,api-key=ghp-xxx'
qshell sbx cr my-template --inline-injection 'type=github,api-key=ghp-xxx'

# Create with a GitHub repository resource mounted into the sandbox
qshell sandbox create my-template \
--resource 'type=github_repository,url=https://github.com/owner/repo.git,mount-path=/workspace/repo,token=ghp-xxx'
qshell sbx cr my-template \
--resource 'url=https://github.com/owner/repo.git,mount-path=/workspace/repo,token=ghp-xxx'`,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
cfg.CmdCfg.CmdId = docs.SandboxCreateType
Expand All @@ -140,6 +150,7 @@ var sandboxCreateCmdBuilder = func(cfg *iqshell.Config) *cobra.Command {
cmd.Flags().BoolVar(&info.AutoPause, "auto-pause", false, "automatically pause sandbox when timeout expires (instead of killing)")
cmd.Flags().StringArrayVar(&info.InjectionRuleID, "injection-rule", nil, "injection rule IDs to apply when creating the sandbox (can be specified multiple times)")
cmd.Flags().StringArrayVar(&info.InlineInjection, "inline-injection", nil, "inline injection spec to apply when creating the sandbox (can be specified multiple times, format: type=<type>,api-key=<key>,base-url=<url>,headers=<k1=v1;k2=v2>)")
cmd.Flags().StringArrayVar(&info.Resources, "resource", nil, "resource to mount before sandbox starts (can be specified multiple times, format: type=github_repository,url=<url>,mount-path=<absPath>,token=<token>; warning: passing tokens via CLI may leak through shell history or process lists)")
return cmd
}

Expand Down
20 changes: 14 additions & 6 deletions cmd/sandbox_injection_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ var injectionRuleCreateCmdBuilder = func(cfg *iqshell.Config) *cobra.Command {

# Create a Qiniu AI API injection rule
qshell sandbox injection-rule create --name qiniu-ai --type qiniu --api-key ak-xxx
qshell sbx ir cr --name qiniu-ai --type qiniu --api-key ak-xxx`,
qshell sbx ir cr --name qiniu-ai --type qiniu --api-key ak-xxx

# Create a GitHub credential injection rule (token passed via --api-key)
qshell sandbox injection-rule create --name github-default --type github --api-key ghp-xxx
qshell sbx ir cr --name github-default --type github --api-key ghp-xxx`,
Run: func(cmd *cobra.Command, args []string) {
cfg.CmdCfg.CmdId = docs.SandboxInjectionRuleCreateType
if !iqshell.CheckAndLoad(cfg, iqshell.CheckAndLoadInfo{}) {
Expand All @@ -113,8 +117,8 @@ var injectionRuleCreateCmdBuilder = func(cfg *iqshell.Config) *cobra.Command {
},
}
cmd.Flags().StringVar(&info.Name, "name", "", "rule name (required, unique per user)")
cmd.Flags().StringVar(&info.Type, "type", "", "injection type: openai, anthropic, gemini, qiniu, http")
cmd.Flags().StringVar(&info.APIKey, "api-key", "", "API key for openai/anthropic/gemini/qiniu injection types (warning: passing secrets via CLI may leak through shell history or process lists)")
cmd.Flags().StringVar(&info.Type, "type", "", "injection type: openai, anthropic, gemini, qiniu, github, http")
cmd.Flags().StringVar(&info.APIKey, "api-key", "", "API key for openai/anthropic/gemini/qiniu, or token for github (warning: passing secrets via CLI may leak through shell history or process lists)")
cmd.Flags().StringVar(&info.BaseURL, "base-url", "", "override base URL or target base URL for http injection")
cmd.Flags().StringVar(&info.Headers, "headers", "", "HTTP headers for custom http injection (comma-separated key=value pairs)")
_ = cmd.MarkFlagRequired("name")
Expand Down Expand Up @@ -143,7 +147,11 @@ var injectionRuleUpdateCmdBuilder = func(cfg *iqshell.Config) *cobra.Command {

# Update to a Qiniu AI API injection
qshell sandbox injection-rule update rule-xxxxxxxxxxxx --type qiniu --api-key ak-new
qshell sbx ir up rule-xxxxxxxxxxxx --type qiniu --api-key ak-new`,
qshell sbx ir up rule-xxxxxxxxxxxx --type qiniu --api-key ak-new

# Update to a GitHub credential injection (token passed via --api-key)
qshell sandbox injection-rule update rule-xxxxxxxxxxxx --type github --api-key ghp-new
qshell sbx ir up rule-xxxxxxxxxxxx --type github --api-key ghp-new`,
Run: func(cmd *cobra.Command, args []string) {
cfg.CmdCfg.CmdId = docs.SandboxInjectionRuleUpdateType
if !iqshell.CheckAndLoad(cfg, iqshell.CheckAndLoadInfo{}) {
Expand All @@ -154,8 +162,8 @@ var injectionRuleUpdateCmdBuilder = func(cfg *iqshell.Config) *cobra.Command {
},
}
cmd.Flags().StringVar(&info.Name, "name", "", "new rule name")
cmd.Flags().StringVar(&info.Type, "type", "", "new injection type: openai, anthropic, gemini, qiniu, http")
cmd.Flags().StringVar(&info.APIKey, "api-key", "", "new API key for openai/anthropic/gemini/qiniu injection types (warning: passing secrets via CLI may leak through shell history or process lists)")
cmd.Flags().StringVar(&info.Type, "type", "", "new injection type: openai, anthropic, gemini, qiniu, github, http")
cmd.Flags().StringVar(&info.APIKey, "api-key", "", "new API key for openai/anthropic/gemini/qiniu, or token for github (warning: passing secrets via CLI may leak through shell history or process lists)")
cmd.Flags().StringVar(&info.BaseURL, "base-url", "", "new base URL or target base URL for http injection")
cmd.Flags().StringVar(&info.Headers, "headers", "", "new HTTP headers for custom http injection (comma-separated key=value pairs)")
return cmd
Expand Down
2 changes: 1 addition & 1 deletion cmd_test/sandbox_injection_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestSandboxInjectionRuleCreateDocumentWithQiniu(t *testing.T) {
testInjectionRuleDocContains(
t,
[]string{"sandbox", "injection-rule", "create"},
"--type <openai|anthropic|gemini|qiniu|http>",
"--type <openai|anthropic|gemini|qiniu|github|http>",
"--name", "qiniu-default",
"--type", "qiniu",
)
Expand Down
33 changes: 28 additions & 5 deletions docs/sandbox_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

# 格式
```
qshell sandbox create [template] [-t <seconds>] [--detach] [-m <metadata>] [-e <KEY=VALUE>...] [--auto-pause] [--injection-rule <ruleID>...] [--inline-injection <spec>...]
qshell sbx cr [template] [-t <seconds>] [--detach] [-m <metadata>] [-e <KEY=VALUE>...] [--auto-pause] [--injection-rule <ruleID>...] [--inline-injection <spec>...]
qshell sandbox create [template] [-t <seconds>] [--detach] [-m <metadata>] [-e <KEY=VALUE>...] [--auto-pause] [--injection-rule <ruleID>...] [--inline-injection <spec>...] [--resource <spec>...]
qshell sbx cr [template] [-t <seconds>] [--detach] [-m <metadata>] [-e <KEY=VALUE>...] [--auto-pause] [--injection-rule <ruleID>...] [--inline-injection <spec>...] [--resource <spec>...]
```

# 帮助文档
Expand All @@ -29,11 +29,18 @@ $ qshell sandbox create --doc
- `--auto-pause`:超时后自动暂停沙箱,而不是终止沙箱
- `--injection-rule`:创建沙箱时附加的注入规则 ID,可多次指定
- `--inline-injection`:创建沙箱时附加的内联注入配置,可多次指定,格式为 `type=<type>,api-key=<key>,base-url=<url>,headers=<k1=v1;k2=v2>`
- `--resource`:沙箱启动前挂载的资源规约,可多次指定,格式为 `type=github_repository,url=<url>,mount-path=<absPath>,token=<token>`(`type` 默认为 `github_repository`,`mount-path` 也可写作 `mount`)。注意:通过 CLI 传递 token 可能泄露到 Shell 历史或进程列表

资源说明:
- `url` 推荐使用 HTTPS 形式(如 `https://github.com/owner/repo.git`);若 URL 本身包含逗号,当前键值串格式无法正确表达
- `mount-path` 必须是沙箱内的绝对路径(POSIX),不接受相对路径;同时给出 `mount-path` 与 `mount` 时两者取值必须一致
- 同一沙箱内多条 `--resource github_repository` 当前必须共用同一 `token`(受 SDK 侧约束)
- `--resource` 与 `--inline-injection type=github` 之间的 token 一致性由平台侧校验,CLI 不做跨参数比较

内联注入说明:
- `type` 支持 `openai`、`anthropic`、`gemini`、`qiniu`、`http`
- `api-key` 可用于 `openai`、`anthropic`、`gemini`、`qiniu`
- `base-url` 可用于覆盖默认目标地址;`type=http` 时必填,`type=qiniu` 默认目标地址为 `api.qnaigc.com`
- `type` 支持 `openai`、`anthropic`、`gemini`、`qiniu`、`github`、`http`
- `api-key` 用于 `openai`、`anthropic`、`gemini`、`qiniu` 的 API Key,以及 `github` 的访问 token(token 仅平台可见,沙箱内不可见明文)
- `base-url` 可用于覆盖默认目标地址;`type=http` 时必填,`type=qiniu` 默认目标地址为 `api.qnaigc.com`;`type=github` 固定匹配 `github.com` / `api.github.com`,不支持配置
- `headers` 仅用于 `type=http`,多个请求头使用分号分隔,例如 `headers=Authorization=Bearer token;X-Env=prod`

# 示例
Expand Down Expand Up @@ -86,3 +93,19 @@ $ qshell sandbox create my-template \
--inline-injection 'type=http,base-url=https://api.example.com,headers=Authorization=Bearer token;X-Env=prod'
$ qshell sbx cr my-template --inline-injection 'type=gemini,api-key=sk-gem'
```

9. 创建时附加 GitHub 凭证注入(token 通过 `api-key` 传入)
```
$ qshell sandbox create my-template --inline-injection 'type=github,api-key=ghp-xxx'
$ qshell sbx cr my-template --inline-injection 'type=github,api-key=ghp-xxx'
```

10. 创建时挂载 GitHub 仓库资源(沙箱启动前由平台拉取仓库快照并挂载到指定路径)
```
$ qshell sandbox create my-template \
--resource 'type=github_repository,url=https://github.com/owner/repo.git,mount-path=/workspace/repo,token=ghp-xxx'
$ qshell sbx cr my-template \
--resource 'url=https://github.com/owner/repo.git,mount-path=/workspace/repo,token=ghp-xxx'
```

> 同一沙箱内多个 `--resource github_repository` 当前必须共用同一 `token`。
16 changes: 11 additions & 5 deletions docs/sandbox_injection_rule_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# 格式

```bash
qshell sandbox injection-rule create --name <name> --type <openai|anthropic|gemini|qiniu|http> [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
qshell sbx ir cr --name <name> --type <openai|anthropic|gemini|qiniu|http> [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
qshell sandbox injection-rule create --name <name> --type <openai|anthropic|gemini|qiniu|github|http> [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
qshell sbx ir cr --name <name> --type <openai|anthropic|gemini|qiniu|github|http> [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
```

# 帮助文档
Expand All @@ -18,9 +18,9 @@ $ qshell sandbox injection-rule create --doc
# 参数

- `--name`:规则名称,必填,同一用户下唯一
- `--type`:注入类型,必填,支持 `openai`、`anthropic`、`gemini`、`qiniu`、`http`
- `--api-key`:`openai`、`anthropic`、`gemini`、`qiniu` 类型使用的 API Key。注意:通过 CLI 传递密钥可能泄露到 Shell 历史或进程列表
- `--base-url`:覆盖默认目标地址,或 `http` 类型的目标基础 URL;`qiniu` 默认为 `api.qnaigc.com`
- `--type`:注入类型,必填,支持 `openai`、`anthropic`、`gemini`、`qiniu`、`github`、`http`
- `--api-key`:`openai`、`anthropic`、`gemini`、`qiniu` 类型使用的 API Key,`github` 类型使用的访问 token;`type=github` 时必填。注意:通过 CLI 传递密钥可能泄露到 Shell 历史或进程列表
- `--base-url`:覆盖默认目标地址,或 `http` 类型的目标基础 URL;`qiniu` 默认为 `api.qnaigc.com`;`github` 类型固定匹配 `github.com` / `api.github.com`,不支持配置
- `--headers`:`http` 类型的请求头,使用逗号分隔的 `key=value` 形式

# 示例
Expand Down Expand Up @@ -48,3 +48,9 @@ $ qshell sandbox injection-rule create --name api-auth --type http --base-url ht
```bash
$ qshell sandbox injection-rule create --name qiniu-ai --type qiniu --api-key ak-xxx
```

创建 GitHub 凭证注入规则(token 通过 `--api-key` 传入,沙箱内不可见明文):

```bash
$ qshell sandbox injection-rule create --name github-default --type github --api-key ghp-xxx
```
12 changes: 9 additions & 3 deletions docs/sandbox_injection_rule_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# 格式

```bash
qshell sandbox injection-rule update <ruleID> [--name <name>] [--type <openai|anthropic|gemini|qiniu|http>] [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
qshell sbx ir up <ruleID> [--name <name>] [--type <openai|anthropic|gemini|qiniu|http>] [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
qshell sandbox injection-rule update <ruleID> [--name <name>] [--type <openai|anthropic|gemini|qiniu|github|http>] [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
qshell sbx ir up <ruleID> [--name <name>] [--type <openai|anthropic|gemini|qiniu|github|http>] [--api-key <apiKey>] [--base-url <baseURL>] [--headers <headers>]
```

# 帮助文档
Expand All @@ -20,7 +20,7 @@ $ qshell sandbox injection-rule update --doc
- `ruleID`:注入规则 ID
- `--name`:新的规则名称
- `--type`:新的注入类型;当需要更新注入配置时必须指定
- `--api-key`:新的 API Key;更新注入配置时必须与 `--type` 一同指定。注意:通过 CLI 传递密钥可能泄露到 Shell 历史或进程列表
- `--api-key`:新的 API Key;更新注入配置时必须与 `--type` 一同指定,且 `type=github` 时必填。注意:通过 CLI 传递密钥可能泄露到 Shell 历史或进程列表
- `--base-url`:新的基础 URL;更新注入配置时必须与 `--type` 一同指定
- `--headers`:新的自定义 HTTP 请求头,使用逗号分隔的 `key=value` 形式;更新时必须与 `--type http` 一同指定

Expand Down Expand Up @@ -51,3 +51,9 @@ $ qshell sandbox injection-rule update rule-xxxxxxxxxxxx --type qiniu --api-key
```bash
$ qshell sandbox injection-rule update rule-xxxxxxxxxxxx --type http --base-url https://api.example.com --headers "Authorization=Bearer newtoken"
```

更新为 GitHub 凭证注入(token 通过 `--api-key` 传入):

```bash
$ qshell sandbox injection-rule update rule-xxxxxxxxxxxx --type github --api-key ghp-new
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/fatih/color v1.18.0
github.com/mitchellh/go-homedir v1.1.0
github.com/muesli/termenv v0.16.0
github.com/qiniu/go-sdk/v7 v7.26.10
github.com/qiniu/go-sdk/v7 v7.26.12
github.com/schollz/progressbar/v3 v3.8.6
github.com/spf13/cast v1.3.1
github.com/spf13/cobra v1.1.3
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,10 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qiniu/go-sdk/v7 v7.26.10 h1:1c2c+grH7b8k5inIDKc95CI8+mAzB5YtfQ/dLOB2nNo=
github.com/qiniu/go-sdk/v7 v7.26.10/go.mod h1:ri7fGwbio0pRDFr8EK5TUpx0DbnpIMJ2bMSDxGWfCbk=
github.com/qiniu/go-sdk/v7 v7.26.11 h1:XVGb5cgqYnNaExCirky+OntL1zvxRxBJuYoWMlnHOuE=
github.com/qiniu/go-sdk/v7 v7.26.11/go.mod h1:ri7fGwbio0pRDFr8EK5TUpx0DbnpIMJ2bMSDxGWfCbk=
github.com/qiniu/go-sdk/v7 v7.26.12 h1:AnWiKjBY62XpULoB/MySKdNmlUo9S9pQB7/0s7QueCo=
github.com/qiniu/go-sdk/v7 v7.26.12/go.mod h1:ri7fGwbio0pRDFr8EK5TUpx0DbnpIMJ2bMSDxGWfCbk=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
Expand Down
13 changes: 13 additions & 0 deletions iqshell/sandbox/injection_rule/operations/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ const (
injectionTypeAnthropic = "anthropic"
injectionTypeGemini = "gemini"
injectionTypeQiniu = "qiniu"
injectionTypeGithub = "github"
injectionTypeHTTP = "http"
)

// githubInjectionTarget 描述 GitHub 注入由平台侧匹配的目标域名集合。
// 当前平台行为固定为 github.com / api.github.com;若后续 SDK 支持自托管 GitHub Enterprise,
// 需要随 SDK 暴露的常量一起同步更新此处。
const githubInjectionTarget = "github.com, api.github.com"

type injectionInput struct {
Type string
APIKey string
Expand All @@ -34,6 +40,7 @@ func buildInjectionSpec(input injectionInput) (sandbox.InjectionSpec, error) {
Anthropic: parts.Anthropic,
Gemini: parts.Gemini,
Qiniu: parts.Qiniu,
Github: parts.Github,
HTTP: parts.HTTP,
}, nil
}
Expand All @@ -52,6 +59,8 @@ func formatInjectionType(spec sandbox.InjectionSpec) string {
return injectionTypeGemini
case spec.Qiniu != nil:
return injectionTypeQiniu
case spec.Github != nil:
return injectionTypeGithub
case spec.HTTP != nil:
return injectionTypeHTTP
default:
Expand All @@ -69,6 +78,8 @@ func formatInjectionTarget(spec sandbox.InjectionSpec) string {
return optionalValue(spec.Gemini.BaseURL, "generativelanguage.googleapis.com")
case spec.Qiniu != nil:
return optionalValue(spec.Qiniu.BaseURL, "api.qnaigc.com")
case spec.Github != nil:
return githubInjectionTarget
case spec.HTTP != nil:
return spec.HTTP.BaseURL
default:
Expand Down Expand Up @@ -98,6 +109,8 @@ func hasAPIKey(spec sandbox.InjectionSpec) bool {
return spec.Gemini.APIKey != nil && strings.TrimSpace(*spec.Gemini.APIKey) != ""
case spec.Qiniu != nil:
return spec.Qiniu.APIKey != nil && strings.TrimSpace(*spec.Qiniu.APIKey) != ""
case spec.Github != nil:
return spec.Github.Token != nil && strings.TrimSpace(*spec.Github.Token) != ""
default:
return false
}
Expand Down
Loading
Loading