mirror of
https://github.com/certd/certd.git
synced 2026-04-03 14:10:54 +08:00
Compare commits
16 Commits
6eb20a1f2e
...
v2-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b109d172f | ||
|
|
6b29972399 | ||
|
|
0fcd3c09fd | ||
|
|
af503442b8 | ||
|
|
c875971b71 | ||
|
|
d1a65922d7 | ||
|
|
6ef34f95d5 | ||
|
|
8b79022179 | ||
|
|
21aec77e5c | ||
|
|
74c5259af8 | ||
|
|
a3e7d4414d | ||
|
|
986d32eb81 | ||
|
|
de0ae14544 | ||
|
|
6b52276fb6 | ||
|
|
a19ea7489c | ||
|
|
14229c2f00 |
@@ -1,115 +0,0 @@
|
||||
---
|
||||
name: using-superpowers
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
|
||||
---
|
||||
|
||||
<SUBAGENT-STOP>
|
||||
If you were dispatched as a subagent to execute a specific task, skip this skill.
|
||||
</SUBAGENT-STOP>
|
||||
|
||||
<EXTREMELY-IMPORTANT>
|
||||
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.
|
||||
|
||||
IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
|
||||
|
||||
This is not negotiable. This is not optional. You cannot rationalize your way out of this.
|
||||
</EXTREMELY-IMPORTANT>
|
||||
|
||||
## Instruction Priority
|
||||
|
||||
Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:
|
||||
|
||||
1. **User's explicit instructions** (CLAUDE.md, GEMINI.md, AGENTS.md, direct requests) — highest priority
|
||||
2. **Superpowers skills** — override default system behavior where they conflict
|
||||
3. **Default system prompt** — lowest priority
|
||||
|
||||
If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "always use TDD," follow the user's instructions. The user is in control.
|
||||
|
||||
## How to Access Skills
|
||||
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.
|
||||
|
||||
**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.
|
||||
|
||||
**In other environments:** Check your platform's documentation for how skills are loaded.
|
||||
|
||||
## Platform Adaptation
|
||||
|
||||
Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
|
||||
|
||||
# Using Skills
|
||||
|
||||
## The Rule
|
||||
|
||||
**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.
|
||||
|
||||
```dot
|
||||
digraph skill_flow {
|
||||
"User message received" [shape=doublecircle];
|
||||
"About to EnterPlanMode?" [shape=doublecircle];
|
||||
"Already brainstormed?" [shape=diamond];
|
||||
"Invoke brainstorming skill" [shape=box];
|
||||
"Might any skill apply?" [shape=diamond];
|
||||
"Invoke Skill tool" [shape=box];
|
||||
"Announce: 'Using [skill] to [purpose]'" [shape=box];
|
||||
"Has checklist?" [shape=diamond];
|
||||
"Create TodoWrite todo per item" [shape=box];
|
||||
"Follow skill exactly" [shape=box];
|
||||
"Respond (including clarifications)" [shape=doublecircle];
|
||||
|
||||
"About to EnterPlanMode?" -> "Already brainstormed?";
|
||||
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
|
||||
"Already brainstormed?" -> "Might any skill apply?" [label="yes"];
|
||||
"Invoke brainstorming skill" -> "Might any skill apply?";
|
||||
|
||||
"User message received" -> "Might any skill apply?";
|
||||
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
|
||||
"Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
|
||||
"Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Follow skill exactly" [label="no"];
|
||||
"Create TodoWrite todo per item" -> "Follow skill exactly";
|
||||
}
|
||||
```
|
||||
|
||||
## Red Flags
|
||||
|
||||
These thoughts mean STOP—you're rationalizing:
|
||||
|
||||
| Thought | Reality |
|
||||
|---------|---------|
|
||||
| "This is just a simple question" | Questions are tasks. Check for skills. |
|
||||
| "I need more context first" | Skill check comes BEFORE clarifying questions. |
|
||||
| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. |
|
||||
| "I can check git/files quickly" | Files lack conversation context. Check for skills. |
|
||||
| "Let me gather information first" | Skills tell you HOW to gather information. |
|
||||
| "This doesn't need a formal skill" | If a skill exists, use it. |
|
||||
| "I remember this skill" | Skills evolve. Read current version. |
|
||||
| "This doesn't count as a task" | Action = task. Check for skills. |
|
||||
| "The skill is overkill" | Simple things become complex. Use it. |
|
||||
| "I'll just do this one thing first" | Check BEFORE doing anything. |
|
||||
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
|
||||
| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |
|
||||
|
||||
## Skill Priority
|
||||
|
||||
When multiple skills could apply, use this order:
|
||||
|
||||
1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
|
||||
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
|
||||
|
||||
"Let's build X" → brainstorming first, then implementation skills.
|
||||
"Fix this bug" → debugging first, then domain-specific skills.
|
||||
|
||||
## Skill Types
|
||||
|
||||
**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.
|
||||
|
||||
**Flexible** (patterns): Adapt principles to context.
|
||||
|
||||
The skill itself tells you which.
|
||||
|
||||
## User Instructions
|
||||
|
||||
Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.
|
||||
@@ -1,100 +0,0 @@
|
||||
# Codex Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
|
||||
| Skill references | Codex equivalent |
|
||||
|-----------------|------------------|
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) |
|
||||
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls |
|
||||
| Task returns result | `wait` |
|
||||
| Task completes automatically | `close_agent` to free slot |
|
||||
| `TodoWrite` (task tracking) | `update_plan` |
|
||||
| `Skill` tool (invoke a skill) | Skills load natively — just follow the instructions |
|
||||
| `Read`, `Write`, `Edit` (files) | Use your native file tools |
|
||||
| `Bash` (run commands) | Use your native shell tools |
|
||||
|
||||
## Subagent dispatch requires multi-agent support
|
||||
|
||||
Add to your Codex config (`~/.codex/config.toml`):
|
||||
|
||||
```toml
|
||||
[features]
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
|
||||
## Named agent dispatch
|
||||
|
||||
Claude Code skills reference named agent types like `superpowers:code-reviewer`.
|
||||
Codex does not have a named agent registry — `spawn_agent` creates generic agents
|
||||
from built-in roles (`default`, `explorer`, `worker`).
|
||||
|
||||
When a skill says to dispatch a named agent type:
|
||||
|
||||
1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's
|
||||
local prompt template like `code-quality-reviewer-prompt.md`)
|
||||
2. Read the prompt content
|
||||
3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.)
|
||||
4. Spawn a `worker` agent with the filled content as the `message`
|
||||
|
||||
| Skill instruction | Codex equivalent |
|
||||
|-------------------|------------------|
|
||||
| `Task tool (superpowers:code-reviewer)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content |
|
||||
| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt |
|
||||
|
||||
### Message framing
|
||||
|
||||
The `message` parameter is user-level input, not a system prompt. Structure it
|
||||
for maximum instruction adherence:
|
||||
|
||||
```
|
||||
Your task is to perform the following. Follow the instructions below exactly.
|
||||
|
||||
<agent-instructions>
|
||||
[filled prompt content from the agent's .md file]
|
||||
</agent-instructions>
|
||||
|
||||
Execute this now. Output ONLY the structured response following the format
|
||||
specified in the instructions above.
|
||||
```
|
||||
|
||||
- Use task-delegation framing ("Your task is...") rather than persona framing ("You are...")
|
||||
- Wrap instructions in XML tags — the model treats tagged blocks as authoritative
|
||||
- End with an explicit execution directive to prevent summarization of the instructions
|
||||
|
||||
### When this workaround can be removed
|
||||
|
||||
This approach compensates for Codex's plugin system not yet supporting an `agents`
|
||||
field in `plugin.json`. When `RawPluginManifest` gains an `agents` field, the
|
||||
plugin can symlink to `agents/` (mirroring the existing `skills/` symlink) and
|
||||
skills can dispatch named agent types directly.
|
||||
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Gemini CLI Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
|
||||
| Skill references | Gemini CLI equivalent |
|
||||
|-----------------|----------------------|
|
||||
| `Read` (file reading) | `read_file` |
|
||||
| `Write` (file creation) | `write_file` |
|
||||
| `Edit` (file editing) | `replace` |
|
||||
| `Bash` (run commands) | `run_shell_command` |
|
||||
| `Grep` (search file content) | `grep_search` |
|
||||
| `Glob` (search files by name) | `glob` |
|
||||
| `TodoWrite` (task tracking) | `write_todos` |
|
||||
| `Skill` tool (invoke a skill) | `activate_skill` |
|
||||
| `WebSearch` | `google_web_search` |
|
||||
| `WebFetch` | `web_fetch` |
|
||||
| `Task` tool (dispatch subagent) | No equivalent — Gemini CLI does not support subagents |
|
||||
|
||||
## No subagent support
|
||||
|
||||
Gemini CLI has no equivalent to Claude Code's `Task` tool. Skills that rely on subagent dispatch (`subagent-driven-development`, `dispatching-parallel-agents`) will fall back to single-session execution via `executing-plans`.
|
||||
|
||||
## Additional Gemini CLI tools
|
||||
|
||||
These tools are available in Gemini CLI but have no Claude Code equivalent:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `list_directory` | List files and subdirectories |
|
||||
| `save_memory` | Persist facts to GEMINI.md across sessions |
|
||||
| `ask_user` | Request structured input from the user |
|
||||
| `tracker_create_task` | Rich task management (create, update, list, visualize) |
|
||||
| `enter_plan_mode` / `exit_plan_mode` | Switch to read-only research mode before making changes |
|
||||
@@ -1,115 +0,0 @@
|
||||
---
|
||||
name: using-superpowers
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
|
||||
---
|
||||
|
||||
<SUBAGENT-STOP>
|
||||
If you were dispatched as a subagent to execute a specific task, skip this skill.
|
||||
</SUBAGENT-STOP>
|
||||
|
||||
<EXTREMELY-IMPORTANT>
|
||||
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.
|
||||
|
||||
IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
|
||||
|
||||
This is not negotiable. This is not optional. You cannot rationalize your way out of this.
|
||||
</EXTREMELY-IMPORTANT>
|
||||
|
||||
## Instruction Priority
|
||||
|
||||
Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:
|
||||
|
||||
1. **User's explicit instructions** (CLAUDE.md, GEMINI.md, AGENTS.md, direct requests) — highest priority
|
||||
2. **Superpowers skills** — override default system behavior where they conflict
|
||||
3. **Default system prompt** — lowest priority
|
||||
|
||||
If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "always use TDD," follow the user's instructions. The user is in control.
|
||||
|
||||
## How to Access Skills
|
||||
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.
|
||||
|
||||
**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.
|
||||
|
||||
**In other environments:** Check your platform's documentation for how skills are loaded.
|
||||
|
||||
## Platform Adaptation
|
||||
|
||||
Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
|
||||
|
||||
# Using Skills
|
||||
|
||||
## The Rule
|
||||
|
||||
**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.
|
||||
|
||||
```dot
|
||||
digraph skill_flow {
|
||||
"User message received" [shape=doublecircle];
|
||||
"About to EnterPlanMode?" [shape=doublecircle];
|
||||
"Already brainstormed?" [shape=diamond];
|
||||
"Invoke brainstorming skill" [shape=box];
|
||||
"Might any skill apply?" [shape=diamond];
|
||||
"Invoke Skill tool" [shape=box];
|
||||
"Announce: 'Using [skill] to [purpose]'" [shape=box];
|
||||
"Has checklist?" [shape=diamond];
|
||||
"Create TodoWrite todo per item" [shape=box];
|
||||
"Follow skill exactly" [shape=box];
|
||||
"Respond (including clarifications)" [shape=doublecircle];
|
||||
|
||||
"About to EnterPlanMode?" -> "Already brainstormed?";
|
||||
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
|
||||
"Already brainstormed?" -> "Might any skill apply?" [label="yes"];
|
||||
"Invoke brainstorming skill" -> "Might any skill apply?";
|
||||
|
||||
"User message received" -> "Might any skill apply?";
|
||||
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
|
||||
"Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
|
||||
"Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Follow skill exactly" [label="no"];
|
||||
"Create TodoWrite todo per item" -> "Follow skill exactly";
|
||||
}
|
||||
```
|
||||
|
||||
## Red Flags
|
||||
|
||||
These thoughts mean STOP—you're rationalizing:
|
||||
|
||||
| Thought | Reality |
|
||||
|---------|---------|
|
||||
| "This is just a simple question" | Questions are tasks. Check for skills. |
|
||||
| "I need more context first" | Skill check comes BEFORE clarifying questions. |
|
||||
| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. |
|
||||
| "I can check git/files quickly" | Files lack conversation context. Check for skills. |
|
||||
| "Let me gather information first" | Skills tell you HOW to gather information. |
|
||||
| "This doesn't need a formal skill" | If a skill exists, use it. |
|
||||
| "I remember this skill" | Skills evolve. Read current version. |
|
||||
| "This doesn't count as a task" | Action = task. Check for skills. |
|
||||
| "The skill is overkill" | Simple things become complex. Use it. |
|
||||
| "I'll just do this one thing first" | Check BEFORE doing anything. |
|
||||
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
|
||||
| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |
|
||||
|
||||
## Skill Priority
|
||||
|
||||
When multiple skills could apply, use this order:
|
||||
|
||||
1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
|
||||
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
|
||||
|
||||
"Let's build X" → brainstorming first, then implementation skills.
|
||||
"Fix this bug" → debugging first, then domain-specific skills.
|
||||
|
||||
## Skill Types
|
||||
|
||||
**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.
|
||||
|
||||
**Flexible** (patterns): Adapt principles to context.
|
||||
|
||||
The skill itself tells you which.
|
||||
|
||||
## User Instructions
|
||||
|
||||
Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.
|
||||
@@ -1,100 +0,0 @@
|
||||
# Codex Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
|
||||
| Skill references | Codex equivalent |
|
||||
|-----------------|------------------|
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) |
|
||||
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls |
|
||||
| Task returns result | `wait` |
|
||||
| Task completes automatically | `close_agent` to free slot |
|
||||
| `TodoWrite` (task tracking) | `update_plan` |
|
||||
| `Skill` tool (invoke a skill) | Skills load natively — just follow the instructions |
|
||||
| `Read`, `Write`, `Edit` (files) | Use your native file tools |
|
||||
| `Bash` (run commands) | Use your native shell tools |
|
||||
|
||||
## Subagent dispatch requires multi-agent support
|
||||
|
||||
Add to your Codex config (`~/.codex/config.toml`):
|
||||
|
||||
```toml
|
||||
[features]
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
|
||||
## Named agent dispatch
|
||||
|
||||
Claude Code skills reference named agent types like `superpowers:code-reviewer`.
|
||||
Codex does not have a named agent registry — `spawn_agent` creates generic agents
|
||||
from built-in roles (`default`, `explorer`, `worker`).
|
||||
|
||||
When a skill says to dispatch a named agent type:
|
||||
|
||||
1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's
|
||||
local prompt template like `code-quality-reviewer-prompt.md`)
|
||||
2. Read the prompt content
|
||||
3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.)
|
||||
4. Spawn a `worker` agent with the filled content as the `message`
|
||||
|
||||
| Skill instruction | Codex equivalent |
|
||||
|-------------------|------------------|
|
||||
| `Task tool (superpowers:code-reviewer)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content |
|
||||
| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt |
|
||||
|
||||
### Message framing
|
||||
|
||||
The `message` parameter is user-level input, not a system prompt. Structure it
|
||||
for maximum instruction adherence:
|
||||
|
||||
```
|
||||
Your task is to perform the following. Follow the instructions below exactly.
|
||||
|
||||
<agent-instructions>
|
||||
[filled prompt content from the agent's .md file]
|
||||
</agent-instructions>
|
||||
|
||||
Execute this now. Output ONLY the structured response following the format
|
||||
specified in the instructions above.
|
||||
```
|
||||
|
||||
- Use task-delegation framing ("Your task is...") rather than persona framing ("You are...")
|
||||
- Wrap instructions in XML tags — the model treats tagged blocks as authoritative
|
||||
- End with an explicit execution directive to prevent summarization of the instructions
|
||||
|
||||
### When this workaround can be removed
|
||||
|
||||
This approach compensates for Codex's plugin system not yet supporting an `agents`
|
||||
field in `plugin.json`. When `RawPluginManifest` gains an `agents` field, the
|
||||
plugin can symlink to `agents/` (mirroring the existing `skills/` symlink) and
|
||||
skills can dispatch named agent types directly.
|
||||
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Gemini CLI Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
|
||||
| Skill references | Gemini CLI equivalent |
|
||||
|-----------------|----------------------|
|
||||
| `Read` (file reading) | `read_file` |
|
||||
| `Write` (file creation) | `write_file` |
|
||||
| `Edit` (file editing) | `replace` |
|
||||
| `Bash` (run commands) | `run_shell_command` |
|
||||
| `Grep` (search file content) | `grep_search` |
|
||||
| `Glob` (search files by name) | `glob` |
|
||||
| `TodoWrite` (task tracking) | `write_todos` |
|
||||
| `Skill` tool (invoke a skill) | `activate_skill` |
|
||||
| `WebSearch` | `google_web_search` |
|
||||
| `WebFetch` | `web_fetch` |
|
||||
| `Task` tool (dispatch subagent) | No equivalent — Gemini CLI does not support subagents |
|
||||
|
||||
## No subagent support
|
||||
|
||||
Gemini CLI has no equivalent to Claude Code's `Task` tool. Skills that rely on subagent dispatch (`subagent-driven-development`, `dispatching-parallel-agents`) will fall back to single-session execution via `executing-plans`.
|
||||
|
||||
## Additional Gemini CLI tools
|
||||
|
||||
These tools are available in Gemini CLI but have no Claude Code equivalent:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `list_directory` | List files and subdirectories |
|
||||
| `save_memory` | Persist facts to GEMINI.md across sessions |
|
||||
| `ask_user` | Request structured input from the user |
|
||||
| `tracker_create_task` | Rich task management (create, update, list, visualize) |
|
||||
| `enter_plan_mode` / `exit_plan_mode` | Switch to read-only research mode before making changes |
|
||||
@@ -163,6 +163,16 @@ async doRequest(req: { action: string, data?: any }) {
|
||||
}
|
||||
```
|
||||
|
||||
--- 开发技巧:实现统一的 API 请求封装
|
||||
|
||||
**好处:**
|
||||
- **代码复用**:避免在每个 API 方法中重复编写相同的 header 设置和错误处理逻辑
|
||||
- **错误处理一致**:统一捕获和处理各种错误情况,确保错误信息格式统一
|
||||
- **日志记录完善**:集中记录详细的错误信息,便于调试和问题排查
|
||||
- **接口调用简化**:调用方只需关注业务逻辑,无需关心底层请求细节
|
||||
- **易于维护**:统一修改 API 调用方式时,只需修改一处代码
|
||||
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **插件命名**:插件名称应简洁明了,反映其功能。
|
||||
@@ -170,9 +180,12 @@ async doRequest(req: { action: string, data?: any }) {
|
||||
3. **日志输出**:必须使用 `this.ctx.logger` 输出日志,而不是 `console`。
|
||||
4. **错误处理**:API 调用失败时应抛出明确的错误信息。
|
||||
5. **测试方法**:实现 `onTestRequest` 方法,以便用户可以测试授权是否正常。
|
||||
6. **统一接口调用方法**:封装统一的 API 请求方法,避免在每个 API 方法调用中重复编写错误处理逻辑。
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 示例 1: 通用授权插件
|
||||
|
||||
```typescript
|
||||
import { AccessInput, BaseAccess, IsAccess, Pager, PageRes, PageSearch } from '@certd/pipeline';
|
||||
import { DomainRecord } from '@certd/plugin-lib';
|
||||
|
||||
@@ -6,9 +6,8 @@ Access:存储用户的第三放应用的授权数据,比如用户名密码
|
||||
Task: 部署任务插件,它继承AbstractTaskPlugin类,被流水线调用execute方法,将证书部署到对应的应用上
|
||||
DnsProvider: DNS提供商插件,它用于在ACME申请证书时给域名添加txt解析记录。
|
||||
|
||||
在开始工作前,请阅读并加载.trae/skills下面的技能,根据skills进行相应的插件开发
|
||||
当开发过程中遇到问题,需要参考plugins目录下的其他插件,或者用户提醒你更好的做法时,你需要总结经验,更新相应的skills,让skills越来越完善,能够在以后得新插件开发中具备指导意义。
|
||||
|
||||
一般调用的api接口文档会比较复杂,你不知道接口是什么时,请务必询问用户,让用户提供API接口文档
|
||||
|
||||
完成开发后无需测试,通知用户自己去测试
|
||||
注意事项:
|
||||
1、使用技能:在开始工作前,请阅读并加载.trae/skills下面的技能,根据skills进行相应的插件开发
|
||||
2、迭代技能:当开发过程用户提醒你更好的做法时,你需要总结经验,更新相应的skills,让skills越来越完善,能够在以后得新插件开发中具备指导意义。
|
||||
3、一般调用的api接口文档会比较复杂,你不知道接口是什么时,请务必询问用户,让用户提供API接口文档
|
||||
4、完成开发后无需测试,通知用户自己去测试
|
||||
@@ -126,6 +126,8 @@ if (isDev()) {
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 示例:通用 DNS Provider
|
||||
|
||||
```typescript
|
||||
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { DemoAccess } from './access.js';
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
---
|
||||
name: using-superpowers
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
|
||||
---
|
||||
|
||||
<SUBAGENT-STOP>
|
||||
If you were dispatched as a subagent to execute a specific task, skip this skill.
|
||||
</SUBAGENT-STOP>
|
||||
|
||||
<EXTREMELY-IMPORTANT>
|
||||
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.
|
||||
|
||||
IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
|
||||
|
||||
This is not negotiable. This is not optional. You cannot rationalize your way out of this.
|
||||
</EXTREMELY-IMPORTANT>
|
||||
|
||||
## Instruction Priority
|
||||
|
||||
Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:
|
||||
|
||||
1. **User's explicit instructions** (CLAUDE.md, GEMINI.md, AGENTS.md, direct requests) — highest priority
|
||||
2. **Superpowers skills** — override default system behavior where they conflict
|
||||
3. **Default system prompt** — lowest priority
|
||||
|
||||
If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "always use TDD," follow the user's instructions. The user is in control.
|
||||
|
||||
## How to Access Skills
|
||||
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.
|
||||
|
||||
**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.
|
||||
|
||||
**In other environments:** Check your platform's documentation for how skills are loaded.
|
||||
|
||||
## Platform Adaptation
|
||||
|
||||
Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
|
||||
|
||||
# Using Skills
|
||||
|
||||
## The Rule
|
||||
|
||||
**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.
|
||||
|
||||
```dot
|
||||
digraph skill_flow {
|
||||
"User message received" [shape=doublecircle];
|
||||
"About to EnterPlanMode?" [shape=doublecircle];
|
||||
"Already brainstormed?" [shape=diamond];
|
||||
"Invoke brainstorming skill" [shape=box];
|
||||
"Might any skill apply?" [shape=diamond];
|
||||
"Invoke Skill tool" [shape=box];
|
||||
"Announce: 'Using [skill] to [purpose]'" [shape=box];
|
||||
"Has checklist?" [shape=diamond];
|
||||
"Create TodoWrite todo per item" [shape=box];
|
||||
"Follow skill exactly" [shape=box];
|
||||
"Respond (including clarifications)" [shape=doublecircle];
|
||||
|
||||
"About to EnterPlanMode?" -> "Already brainstormed?";
|
||||
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
|
||||
"Already brainstormed?" -> "Might any skill apply?" [label="yes"];
|
||||
"Invoke brainstorming skill" -> "Might any skill apply?";
|
||||
|
||||
"User message received" -> "Might any skill apply?";
|
||||
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
|
||||
"Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
|
||||
"Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Follow skill exactly" [label="no"];
|
||||
"Create TodoWrite todo per item" -> "Follow skill exactly";
|
||||
}
|
||||
```
|
||||
|
||||
## Red Flags
|
||||
|
||||
These thoughts mean STOP—you're rationalizing:
|
||||
|
||||
| Thought | Reality |
|
||||
|---------|---------|
|
||||
| "This is just a simple question" | Questions are tasks. Check for skills. |
|
||||
| "I need more context first" | Skill check comes BEFORE clarifying questions. |
|
||||
| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. |
|
||||
| "I can check git/files quickly" | Files lack conversation context. Check for skills. |
|
||||
| "Let me gather information first" | Skills tell you HOW to gather information. |
|
||||
| "This doesn't need a formal skill" | If a skill exists, use it. |
|
||||
| "I remember this skill" | Skills evolve. Read current version. |
|
||||
| "This doesn't count as a task" | Action = task. Check for skills. |
|
||||
| "The skill is overkill" | Simple things become complex. Use it. |
|
||||
| "I'll just do this one thing first" | Check BEFORE doing anything. |
|
||||
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
|
||||
| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |
|
||||
|
||||
## Skill Priority
|
||||
|
||||
When multiple skills could apply, use this order:
|
||||
|
||||
1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
|
||||
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
|
||||
|
||||
"Let's build X" → brainstorming first, then implementation skills.
|
||||
"Fix this bug" → debugging first, then domain-specific skills.
|
||||
|
||||
## Skill Types
|
||||
|
||||
**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.
|
||||
|
||||
**Flexible** (patterns): Adapt principles to context.
|
||||
|
||||
The skill itself tells you which.
|
||||
|
||||
## User Instructions
|
||||
|
||||
Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.
|
||||
@@ -1,100 +0,0 @@
|
||||
# Codex Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
|
||||
| Skill references | Codex equivalent |
|
||||
|-----------------|------------------|
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) |
|
||||
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls |
|
||||
| Task returns result | `wait` |
|
||||
| Task completes automatically | `close_agent` to free slot |
|
||||
| `TodoWrite` (task tracking) | `update_plan` |
|
||||
| `Skill` tool (invoke a skill) | Skills load natively — just follow the instructions |
|
||||
| `Read`, `Write`, `Edit` (files) | Use your native file tools |
|
||||
| `Bash` (run commands) | Use your native shell tools |
|
||||
|
||||
## Subagent dispatch requires multi-agent support
|
||||
|
||||
Add to your Codex config (`~/.codex/config.toml`):
|
||||
|
||||
```toml
|
||||
[features]
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
|
||||
## Named agent dispatch
|
||||
|
||||
Claude Code skills reference named agent types like `superpowers:code-reviewer`.
|
||||
Codex does not have a named agent registry — `spawn_agent` creates generic agents
|
||||
from built-in roles (`default`, `explorer`, `worker`).
|
||||
|
||||
When a skill says to dispatch a named agent type:
|
||||
|
||||
1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's
|
||||
local prompt template like `code-quality-reviewer-prompt.md`)
|
||||
2. Read the prompt content
|
||||
3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.)
|
||||
4. Spawn a `worker` agent with the filled content as the `message`
|
||||
|
||||
| Skill instruction | Codex equivalent |
|
||||
|-------------------|------------------|
|
||||
| `Task tool (superpowers:code-reviewer)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content |
|
||||
| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt |
|
||||
|
||||
### Message framing
|
||||
|
||||
The `message` parameter is user-level input, not a system prompt. Structure it
|
||||
for maximum instruction adherence:
|
||||
|
||||
```
|
||||
Your task is to perform the following. Follow the instructions below exactly.
|
||||
|
||||
<agent-instructions>
|
||||
[filled prompt content from the agent's .md file]
|
||||
</agent-instructions>
|
||||
|
||||
Execute this now. Output ONLY the structured response following the format
|
||||
specified in the instructions above.
|
||||
```
|
||||
|
||||
- Use task-delegation framing ("Your task is...") rather than persona framing ("You are...")
|
||||
- Wrap instructions in XML tags — the model treats tagged blocks as authoritative
|
||||
- End with an explicit execution directive to prevent summarization of the instructions
|
||||
|
||||
### When this workaround can be removed
|
||||
|
||||
This approach compensates for Codex's plugin system not yet supporting an `agents`
|
||||
field in `plugin.json`. When `RawPluginManifest` gains an `agents` field, the
|
||||
plugin can symlink to `agents/` (mirroring the existing `skills/` symlink) and
|
||||
skills can dispatch named agent types directly.
|
||||
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Gemini CLI Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
|
||||
| Skill references | Gemini CLI equivalent |
|
||||
|-----------------|----------------------|
|
||||
| `Read` (file reading) | `read_file` |
|
||||
| `Write` (file creation) | `write_file` |
|
||||
| `Edit` (file editing) | `replace` |
|
||||
| `Bash` (run commands) | `run_shell_command` |
|
||||
| `Grep` (search file content) | `grep_search` |
|
||||
| `Glob` (search files by name) | `glob` |
|
||||
| `TodoWrite` (task tracking) | `write_todos` |
|
||||
| `Skill` tool (invoke a skill) | `activate_skill` |
|
||||
| `WebSearch` | `google_web_search` |
|
||||
| `WebFetch` | `web_fetch` |
|
||||
| `Task` tool (dispatch subagent) | No equivalent — Gemini CLI does not support subagents |
|
||||
|
||||
## No subagent support
|
||||
|
||||
Gemini CLI has no equivalent to Claude Code's `Task` tool. Skills that rely on subagent dispatch (`subagent-driven-development`, `dispatching-parallel-agents`) will fall back to single-session execution via `executing-plans`.
|
||||
|
||||
## Additional Gemini CLI tools
|
||||
|
||||
These tools are available in Gemini CLI but have no Claude Code equivalent:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `list_directory` | List files and subdirectories |
|
||||
| `save_memory` | Persist facts to GEMINI.md across sessions |
|
||||
| `ask_user` | Request structured input from the user |
|
||||
| `tracker_create_task` | Rich task management (create, update, list, visualize) |
|
||||
| `enter_plan_mode` / `exit_plan_mode` | Switch to read-only research mode before making changes |
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复某些情况下报没有匹配到任何校验方式的bug ([fe02ce7](https://github.com/certd/certd/commit/fe02ce7b64cf23c4dc4c30daccd5330059a35e9a))
|
||||
* 修复上传头像退出登录的bug ([6eb20a1](https://github.com/certd/certd/commit/6eb20a1f2e31d984d9135edbf39c97cdd15621f9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云CDN部署支持根据证书域名自动匹配部署 ([a68301e](https://github.com/certd/certd/commit/a68301e4dcea8b7391ad751aa57555d566297ad9))
|
||||
* 阿里云dcdn支持根据证书域名匹配模式 ([df012de](https://github.com/certd/certd/commit/df012dec90590ecba85a69ed6355cfa8382c1da3))
|
||||
* 支持部署证书到百度CCE ([a19ea74](https://github.com/certd/certd/commit/a19ea7489c01cdbf795fb51f804bd6d00389f604))
|
||||
* dcdn自动匹配部署,支持新增域名感知 ([c6a988b](https://github.com/certd/certd/commit/c6a988bc925886bd7163c1270f2b7a10a57b1c5b))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -211,3 +211,4 @@ https://certd.handfree.work/
|
||||
| --------- |--------- |----------- |
|
||||
| [fast-crud](https://gitee.com/fast-crud/fast-crud/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/fast-crud/fast-crud?logo=github"/> | 基于vue3的crud快速开发框架 |
|
||||
| [dev-sidecar](https://github.com/docmirror/dev-sidecar/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"/> | 直连访问github工具,无需FQ,解决github无法访问的问题 |
|
||||
| [winsvc-manager](https://github.com/greper/winsvc-manager/) | <img alt="GitHub stars" src="https://img.shields.io/github/stars/greper/winsvc-manager?logo=github"/> | 可视化包装应用成为一个Windows服务,使其后台运行 |
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复某些情况下报没有匹配到任何校验方式的bug ([fe02ce7](https://github.com/certd/certd/commit/fe02ce7b64cf23c4dc4c30daccd5330059a35e9a))
|
||||
* 修复上传头像退出登录的bug ([6eb20a1](https://github.com/certd/certd/commit/6eb20a1f2e31d984d9135edbf39c97cdd15621f9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云CDN部署支持根据证书域名自动匹配部署 ([a68301e](https://github.com/certd/certd/commit/a68301e4dcea8b7391ad751aa57555d566297ad9))
|
||||
* 阿里云dcdn支持根据证书域名匹配模式 ([df012de](https://github.com/certd/certd/commit/df012dec90590ecba85a69ed6355cfa8382c1da3))
|
||||
* 支持部署证书到百度CCE ([a19ea74](https://github.com/certd/certd/commit/a19ea7489c01cdbf795fb51f804bd6d00389f604))
|
||||
* dcdn自动匹配部署,支持新增域名感知 ([c6a988b](https://github.com/certd/certd/commit/c6a988bc925886bd7163c1270f2b7a10a57b1c5b))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 任务插件
|
||||
共 `128` 款任务插件
|
||||
共 `129` 款任务插件
|
||||
## 1. 证书申请
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
@@ -155,8 +155,9 @@
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **百度云-部署证书到负载均衡** | 部署到百度云负载均衡,包括BLB、APPBLB |
|
||||
| 2.| **百度云-部署证书到CDN** | 部署到百度云CDN |
|
||||
| 3.| **百度云-上传到证书托管** | 上传证书到百度云证书托管中心 |
|
||||
| 2.| **百度云-部署到CCE** | 部署到百度云CCE集群Ingress等通过Secret管理证书的应用 |
|
||||
| 3.| **百度云-部署证书到CDN** | 部署到百度云CDN |
|
||||
| 4.| **百度云-上传到证书托管** | 上传证书到百度云证书托管中心 |
|
||||
## 12. 七牛云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.39.7"
|
||||
"version": "1.39.8"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/publishlab/node-acme-client/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.39.7](https://github.com/publishlab/node-acme-client/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.9.0",
|
||||
@@ -70,5 +70,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:02
|
||||
23:54
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -47,5 +47,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ export function createAxiosService({ logger }: { logger: ILogger }) {
|
||||
}
|
||||
|
||||
const originalRequest = error.config || {};
|
||||
logger.info(`config`, originalRequest);
|
||||
// logger.info(`config`, originalRequest);
|
||||
const retry = originalRequest.retry || {};
|
||||
if (retry.status && retry.status.includes(status)) {
|
||||
if (retry.max > 0 && retry.count < retry.max) {
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云CDN部署支持根据证书域名自动匹配部署 ([a68301e](https://github.com/certd/certd/commit/a68301e4dcea8b7391ad751aa57555d566297ad9))
|
||||
* 阿里云dcdn支持根据证书域名匹配模式 ([df012de](https://github.com/certd/certd/commit/df012dec90590ecba85a69ed6355cfa8382c1da3))
|
||||
* dcdn自动匹配部署,支持新增域名感知 ([c6a988b](https://github.com/certd/certd/commit/c6a988bc925886bd7163c1270f2b7a10a57b1c5b))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -18,8 +18,8 @@
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/plus-core": "^1.39.7",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@certd/plus-core": "^1.39.8",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -45,5 +45,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { Registrable } from "../registry/index.js";
|
||||
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.js";
|
||||
import { FileStore } from "../core/file-store.js";
|
||||
import { accessRegistry, IAccessService } from "../access/index.js";
|
||||
import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
|
||||
import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js";
|
||||
import { domainUtils, HttpRequestConfig, ILogger, logger, optionsUtils, utils } from "@certd/basic";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
import { domainUtils, HttpClient, HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
|
||||
import dayjs from "dayjs";
|
||||
import { IPluginConfigService } from "../service/config.js";
|
||||
import { cloneDeep, upperFirst } from "lodash-es";
|
||||
import { INotificationService } from "../notification/index.js";
|
||||
import { TaskEmitter } from "../service/emit.js";
|
||||
import { accessRegistry, IAccessService } from "../access/index.js";
|
||||
import { PageSearch } from "../context/index.js";
|
||||
import { FileStore } from "../core/file-store.js";
|
||||
import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js";
|
||||
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.js";
|
||||
import { INotificationService } from "../notification/index.js";
|
||||
import { Registrable } from "../registry/index.js";
|
||||
import { IPluginConfigService } from "../service/config.js";
|
||||
import { TaskEmitter } from "../service/emit.js";
|
||||
import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
|
||||
|
||||
export type PluginRequestHandleReq<T = any> = {
|
||||
typeName: string;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -24,5 +24,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
@@ -56,5 +56,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持部署证书到百度CCE ([a19ea74](https://github.com/certd/certd/commit/a19ea7489c01cdbf795fb51f804bd6d00389f604))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -14,10 +14,11 @@
|
||||
"build3": "rollup -c",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"pub": "npm publish"
|
||||
"pub": "npm publish",
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -32,5 +33,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ export class K8sClient {
|
||||
const yml = loadYaml<KubernetesObject>(manifest);
|
||||
const client = this.getKubeClient();
|
||||
try {
|
||||
this.logger.info("apply yaml:", yml);
|
||||
await client.create(yml);
|
||||
} catch (e) {
|
||||
this.logger.error("apply error", e.response?.body);
|
||||
if (e.response?.body?.reason === "AlreadyExists") {
|
||||
//patch
|
||||
this.logger.info("patch existing resource: ", yml.metadata?.name);
|
||||
@@ -70,13 +70,26 @@ export class K8sClient {
|
||||
yml.metadata = {};
|
||||
}
|
||||
yml.metadata.resourceVersion = existing.body.metadata.resourceVersion;
|
||||
await client.patch(yml);
|
||||
return;
|
||||
const res = await client.patch(yml);
|
||||
return res?.body;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async applyPatch(manifest: string) {
|
||||
const yml = loadYaml<KubernetesObject>(manifest);
|
||||
const client = this.getKubeClient();
|
||||
this.logger.info("patch yaml:", yml);
|
||||
const existing = await client.read(yml as any);
|
||||
if (!yml.metadata) {
|
||||
yml.metadata = {};
|
||||
}
|
||||
yml.metadata.resourceVersion = existing.body.metadata.resourceVersion;
|
||||
const res = await client.patch(yml);
|
||||
return res?.body;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param localRecords { [domain]:{ip:'xxx.xx.xxx'} }
|
||||
@@ -112,6 +125,7 @@ export class K8sClient {
|
||||
*/
|
||||
async createSecret(opts: { namespace: string; body: V1Secret }) {
|
||||
const namespace = opts.namespace || "default";
|
||||
this.logger.info("create secret:", opts.body.metadata);
|
||||
const created = await this.client.createNamespacedSecret(namespace, opts.body);
|
||||
this.logger.info("new secrets:", opts.body.metadata);
|
||||
return created.body;
|
||||
@@ -152,6 +166,8 @@ export class K8sClient {
|
||||
this.logger.info(`secret ${secretName} 已创建`);
|
||||
return res;
|
||||
}
|
||||
|
||||
throw new Error(`secret ${secretName} 不存在`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -28,11 +28,11 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.39.7",
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/pipeline": "^1.39.7",
|
||||
"@certd/plugin-lib": "^1.39.7",
|
||||
"@certd/plus-core": "^1.39.7",
|
||||
"@certd/acme-client": "^1.39.8",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@certd/pipeline": "^1.39.8",
|
||||
"@certd/plugin-lib": "^1.39.8",
|
||||
"@certd/plus-core": "^1.39.8",
|
||||
"@midwayjs/cache": "3.14.0",
|
||||
"@midwayjs/core": "3.20.11",
|
||||
"@midwayjs/i18n": "3.20.13",
|
||||
@@ -64,5 +64,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -17,10 +17,10 @@
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.39.7",
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/pipeline": "^1.39.7",
|
||||
"@certd/plugin-lib": "^1.39.7",
|
||||
"@certd/acme-client": "^1.39.8",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@certd/pipeline": "^1.39.8",
|
||||
"@certd/plugin-lib": "^1.39.8",
|
||||
"psl": "^1.9.0",
|
||||
"punycode.js": "^2.3.1"
|
||||
},
|
||||
@@ -38,5 +38,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* dcdn自动匹配部署,支持新增域名感知 ([c6a988b](https://github.com/certd/certd/commit/c6a988bc925886bd7163c1270f2b7a10a57b1c5b))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -22,10 +22,10 @@
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@alicloud/tea-util": "^1.4.11",
|
||||
"@aws-sdk/client-s3": "^3.964.0",
|
||||
"@certd/acme-client": "^1.39.7",
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/pipeline": "^1.39.7",
|
||||
"@certd/plus-core": "^1.39.7",
|
||||
"@certd/acme-client": "^1.39.8",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@certd/pipeline": "^1.39.8",
|
||||
"@certd/plus-core": "^1.39.8",
|
||||
"@kubernetes/client-node": "0.21.0",
|
||||
"ali-oss": "^6.22.0",
|
||||
"basic-ftp": "^5.0.5",
|
||||
@@ -57,5 +57,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "adc3e6118b941818926705c3536babfca117c247"
|
||||
"gitHead": "de0ae14544f1c3da4923dddc6a1a3bea4db295e7"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复上传头像退出登录的bug ([6eb20a1](https://github.com/certd/certd/commit/6eb20a1f2e31d984d9135edbf39c97cdd15621f9))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云dcdn支持根据证书域名匹配模式 ([df012de](https://github.com/certd/certd/commit/df012dec90590ecba85a69ed6355cfa8382c1da3))
|
||||
* dcdn自动匹配部署,支持新增域名感知 ([c6a988b](https://github.com/certd/certd/commit/c6a988bc925886bd7163c1270f2b7a10a57b1c5b))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -106,8 +106,8 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.39.7",
|
||||
"@certd/pipeline": "^1.39.7",
|
||||
"@certd/lib-iframe": "^1.39.8",
|
||||
"@certd/pipeline": "^1.39.8",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -21,7 +21,8 @@ import { defineComponent, reactive, ref, watch, inject } from "vue";
|
||||
import CertAccessModal from "./access/index.vue";
|
||||
import { createAccessApi } from "../api";
|
||||
import { message } from "ant-design-vue";
|
||||
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import { useProjectStore } from "/@/store/project";
|
||||
export default defineComponent({
|
||||
name: "AccessSelector",
|
||||
components: { CertAccessModal },
|
||||
@@ -71,11 +72,27 @@ export default defineComponent({
|
||||
emitValue(null);
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
const projectStore = useProjectStore();
|
||||
|
||||
async function emitValue(value) {
|
||||
if (pipeline && pipeline?.value && target?.value && pipeline.value.userId !== target.value.userId) {
|
||||
message.error("对不起,您不能修改他人流水线的授权");
|
||||
return;
|
||||
const userId = userStore.userInfo.id;
|
||||
const isEnterprice = projectStore.isEnterprise;
|
||||
if (pipeline?.value) {
|
||||
if (isEnterprice) {
|
||||
const projectId = projectStore.currentProjectId;
|
||||
if (pipeline?.value?.projectId !== projectId) {
|
||||
message.error(`对不起,您不能修改其他项目流水线的授权`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (pipeline?.value && pipeline.value.userId !== userId) {
|
||||
message.error(`对不起,您不能修改他人流水线的授权`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
selectedId.value = "";
|
||||
target.value = null;
|
||||
|
||||
@@ -48,6 +48,7 @@ import createCrudOptions from "../crud";
|
||||
import { addonProvide } from "../common";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import { useI18n } from "/src/locales";
|
||||
import { useProjectStore } from "/@/store/project";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -127,13 +128,24 @@ function clear() {
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const projectStore = useProjectStore();
|
||||
async function emitValue(value: any) {
|
||||
// target.value = optionsDictRef.dataMap[value];
|
||||
const userId = userStore.userInfo.id;
|
||||
if (pipeline?.value && pipeline.value.userId !== userId) {
|
||||
message.error(`对不起,您不能修改他人流水线的${props.addonType}设置`);
|
||||
return;
|
||||
if (pipeline.value) {
|
||||
const userId = userStore.userInfo.id;
|
||||
const isEnterprice = projectStore.isEnterprise;
|
||||
if (isEnterprice) {
|
||||
const projectId = projectStore.currentProjectId;
|
||||
if (pipeline?.value?.projectId !== projectId) {
|
||||
message.error(`对不起,您不能修改其他项目流水线的${props.addonType}设置`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (pipeline?.value && pipeline.value.userId !== userId) {
|
||||
message.error(`对不起,您不能修改他人流水线的${props.addonType}设置`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
emit("change", value);
|
||||
emit("update:modelValue", value);
|
||||
|
||||
@@ -42,6 +42,7 @@ import createCrudOptions from "../crud";
|
||||
import { notificationProvide } from "/@/views/certd/notification/common";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import { useI18n } from "/src/locales";
|
||||
import { useProjectStore } from "/@/store/project";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -127,13 +128,23 @@ function clear() {
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const projectStore = useProjectStore();
|
||||
async function emitValue(value: any) {
|
||||
// target.value = optionsDictRef.dataMap[value];
|
||||
const userId = userStore.userInfo.id;
|
||||
if (pipeline?.value && pipeline.value.userId !== userId) {
|
||||
message.error("对不起,您不能修改他人流水线的通知");
|
||||
return;
|
||||
const isEnterprice = projectStore.isEnterprise;
|
||||
|
||||
if (isEnterprice) {
|
||||
const projectId = projectStore.currentProjectId;
|
||||
if (pipeline?.value?.projectId !== projectId) {
|
||||
message.error("对不起,您不能修改其他项目流水线的通知");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (pipeline?.value?.userId !== userId) {
|
||||
message.error("对不起,您不能修改他人流水线的通知");
|
||||
return;
|
||||
}
|
||||
}
|
||||
emit("change", value);
|
||||
emit("update:modelValue", value);
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.8](https://github.com/certd/certd/compare/v1.39.7...v1.39.8) (2026-03-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复某些情况下报没有匹配到任何校验方式的bug ([fe02ce7](https://github.com/certd/certd/commit/fe02ce7b64cf23c4dc4c30daccd5330059a35e9a))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 阿里云CDN部署支持根据证书域名自动匹配部署 ([a68301e](https://github.com/certd/certd/commit/a68301e4dcea8b7391ad751aa57555d566297ad9))
|
||||
* 阿里云dcdn支持根据证书域名匹配模式 ([df012de](https://github.com/certd/certd/commit/df012dec90590ecba85a69ed6355cfa8382c1da3))
|
||||
* 支持部署证书到百度CCE ([a19ea74](https://github.com/certd/certd/commit/a19ea7489c01cdbf795fb51f804bd6d00389f604))
|
||||
* dcdn自动匹配部署,支持新增域名感知 ([c6a988b](https://github.com/certd/certd/commit/c6a988bc925886bd7163c1270f2b7a10a57b1c5b))
|
||||
|
||||
## [1.39.7](https://github.com/certd/certd/compare/v1.39.6...v1.39.7) (2026-03-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -7,6 +7,7 @@ title: 阿里云-部署证书至CDN
|
||||
icon: svg:icon-aliyun
|
||||
group: aliyun
|
||||
desc: 自动部署域名证书至阿里云CDN
|
||||
runStrategy: 0
|
||||
input:
|
||||
endpoint:
|
||||
title: 证书服务接入点
|
||||
@@ -59,36 +60,6 @@ input:
|
||||
type: aliyun
|
||||
required: true
|
||||
order: 0
|
||||
domainName:
|
||||
title: CDN加速域名
|
||||
component:
|
||||
name: remote-select
|
||||
vModel: value
|
||||
mode: tags
|
||||
type: plugin
|
||||
typeName: DeployCertToAliyunCDN
|
||||
action: onGetDomainList
|
||||
search: false
|
||||
pager: false
|
||||
multi: true
|
||||
watches:
|
||||
- certDomains
|
||||
- accessId
|
||||
- certDomains
|
||||
- accessId
|
||||
required: true
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
component:{
|
||||
form: ctx.compute(({form})=>{
|
||||
return form
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
helper: 你在阿里云上配置的CDN加速域名,比如:certd.docmirror.cn
|
||||
order: 0
|
||||
certRegion:
|
||||
title: 证书所在地域
|
||||
helper: cn-hangzhou和ap-southeast-1,默认cn-hangzhou。国际站用户建议使用ap-southeast-1。
|
||||
@@ -106,7 +77,49 @@ input:
|
||||
title: 证书名称
|
||||
helper: 上传后将以此名称作为前缀备注
|
||||
order: 0
|
||||
output: {}
|
||||
domainMatchMode:
|
||||
title: 域名匹配模式
|
||||
helper: 根据证书匹配:根据证书域名自动匹配DCDN加速域名自动部署,新增加速域名自动感知,自动新增部署
|
||||
component:
|
||||
name: a-select
|
||||
options:
|
||||
- label: 手动选择
|
||||
value: manual
|
||||
- label: 根据证书匹配
|
||||
value: auto
|
||||
value: manual
|
||||
order: 0
|
||||
domainName:
|
||||
title: CDN加速域名
|
||||
component:
|
||||
name: remote-select
|
||||
vModel: value
|
||||
mode: tags
|
||||
type: plugin
|
||||
typeName: DeployCertToAliyunCDN
|
||||
action: onGetDomainList
|
||||
search: false
|
||||
pager: true
|
||||
multi: true
|
||||
watches:
|
||||
- certDomains
|
||||
- accessId
|
||||
- certDomains
|
||||
- accessId
|
||||
required: true
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.domainMatchMode === "manual"
|
||||
})
|
||||
}
|
||||
|
||||
helper: 你在阿里云上配置的CDN加速域名,比如:certd.docmirror.cn
|
||||
order: 0
|
||||
output:
|
||||
deployedList:
|
||||
title: 已部署过的DCDN加速域名
|
||||
pluginType: deploy
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-aliyun/plugin/deploy-to-cdn/index.js
|
||||
|
||||
@@ -7,6 +7,7 @@ title: 阿里云-部署证书至DCDN
|
||||
icon: svg:icon-aliyun
|
||||
group: aliyun
|
||||
desc: 依赖证书申请前置任务,自动部署域名证书至阿里云DCDN
|
||||
runStrategy: 0
|
||||
input:
|
||||
cert:
|
||||
title: 域名证书
|
||||
@@ -47,6 +48,18 @@ input:
|
||||
title: 证书名称
|
||||
helper: 上传后将以此名称作为前缀备注
|
||||
order: 0
|
||||
domainMatchMode:
|
||||
title: 域名匹配模式
|
||||
helper: 根据证书匹配:根据证书域名自动匹配DCDN加速域名自动部署,新增加速域名自动感知,自动新增部署
|
||||
component:
|
||||
name: a-select
|
||||
options:
|
||||
- label: 手动选择
|
||||
value: manual
|
||||
- label: 根据证书匹配
|
||||
value: auto
|
||||
value: manual
|
||||
order: 0
|
||||
domainName:
|
||||
title: DCDN加速域名
|
||||
component:
|
||||
@@ -56,7 +69,7 @@ input:
|
||||
type: plugin
|
||||
action: onGetDomainList
|
||||
search: false
|
||||
pager: false
|
||||
pager: true
|
||||
multi: true
|
||||
watches:
|
||||
- certDomains
|
||||
@@ -66,17 +79,17 @@ input:
|
||||
required: true
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
component:{
|
||||
form: ctx.compute(({form})=>{
|
||||
return form
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.domainMatchMode === "manual"
|
||||
})
|
||||
}
|
||||
|
||||
helper: 你在阿里云上配置的DCDN加速域名,比如:certd.docmirror.cn
|
||||
order: 0
|
||||
output: {}
|
||||
output:
|
||||
deployedList:
|
||||
title: 已部署过的DCDN加速域名
|
||||
pluginType: deploy
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-aliyun/plugin/deploy-to-dcdn/index.js
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
showRunStrategy: false
|
||||
default:
|
||||
strategy:
|
||||
runStrategy: 1
|
||||
name: DeployCertToBaiduCce
|
||||
title: 百度云-部署到CCE
|
||||
icon: ant-design:cloud-outlined
|
||||
desc: 部署到百度云CCE集群Ingress等通过Secret管理证书的应用
|
||||
group: baidu
|
||||
needPlus: true
|
||||
input:
|
||||
cert:
|
||||
title: 域名证书
|
||||
helper: 请选择前置任务输出的域名证书
|
||||
component:
|
||||
name: output-selector
|
||||
from:
|
||||
- ':cert:'
|
||||
required: true
|
||||
order: 0
|
||||
accessId:
|
||||
title: Access授权
|
||||
helper: 百度云授权AccessKey、SecretKey
|
||||
component:
|
||||
name: access-selector
|
||||
type: baidu
|
||||
required: true
|
||||
order: 0
|
||||
regionId:
|
||||
title: 大区
|
||||
component:
|
||||
name: a-auto-complete
|
||||
vModel: value
|
||||
options:
|
||||
- value: bj
|
||||
label: 北京
|
||||
- value: gz
|
||||
label: 广州
|
||||
- value: su
|
||||
label: 苏州
|
||||
- value: bd
|
||||
label: 保定
|
||||
- value: fwh
|
||||
label: 武汉
|
||||
- value: hkg
|
||||
label: 香港
|
||||
- value: yq
|
||||
label: 阳泉
|
||||
- value: cd
|
||||
label: 成都
|
||||
- value: nj
|
||||
label: 南京
|
||||
placeholder: 集群所属大区
|
||||
required: true
|
||||
order: 0
|
||||
clusterId:
|
||||
title: 集群id
|
||||
component:
|
||||
placeholder: 集群id
|
||||
required: true
|
||||
order: 0
|
||||
secretName:
|
||||
title: 保密字典Id
|
||||
component:
|
||||
placeholder: 保密字典Id
|
||||
helper: 原本存储证书的secret的name
|
||||
required: true
|
||||
order: 0
|
||||
namespace:
|
||||
title: 命名空间
|
||||
value: default
|
||||
component:
|
||||
placeholder: 命名空间
|
||||
required: true
|
||||
order: 0
|
||||
kubeconfigType:
|
||||
title: Kubeconfig类型
|
||||
value: public
|
||||
component:
|
||||
name: a-auto-complete
|
||||
vModel: value
|
||||
options:
|
||||
- value: vpc
|
||||
label: VPC私网IP (BLB VPCIP)
|
||||
- value: public
|
||||
label: 公网IP (BLB EIP)
|
||||
placeholder: 选择集群连接端点类型
|
||||
helper: VPC类型使用私网IP连接,需要certd运行在同一网络环境;public类型使用公网IP连接
|
||||
required: true
|
||||
order: 0
|
||||
skipTLSVerify:
|
||||
title: 忽略证书校验
|
||||
required: false
|
||||
helper: 是否忽略证书校验
|
||||
component:
|
||||
name: a-switch
|
||||
vModel: checked
|
||||
order: 0
|
||||
createOnNotFound:
|
||||
title: Secret自动创建
|
||||
helper: 如果Secret不存在,则创建,百度云的自动创建secret有问题
|
||||
value: false
|
||||
component:
|
||||
name: a-switch
|
||||
vModel: checked
|
||||
order: 0
|
||||
output: {}
|
||||
pluginType: deploy
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-plus/baidu/plugins/plugin-deploy-to-cce.js
|
||||
@@ -35,6 +35,19 @@ input:
|
||||
type: k8s
|
||||
required: true
|
||||
order: 0
|
||||
strategy:
|
||||
title: 应用策略
|
||||
helper: 选择使用apply(创建或更新)还是patch(补丁更新)
|
||||
component:
|
||||
name: a-select
|
||||
options:
|
||||
- label: apply(创建)
|
||||
value: apply
|
||||
- label: patch(更新)
|
||||
value: patch
|
||||
value: apply
|
||||
required: true
|
||||
order: 0
|
||||
yamlContent:
|
||||
title: yaml
|
||||
required: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.39.7",
|
||||
"version": "1.39.8",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -50,20 +50,20 @@
|
||||
"@aws-sdk/client-route-53": "^3.964.0",
|
||||
"@aws-sdk/client-s3": "^3.964.0",
|
||||
"@aws-sdk/client-sts": "^3.990.0",
|
||||
"@certd/acme-client": "^1.39.7",
|
||||
"@certd/basic": "^1.39.7",
|
||||
"@certd/commercial-core": "^1.39.7",
|
||||
"@certd/acme-client": "^1.39.8",
|
||||
"@certd/basic": "^1.39.8",
|
||||
"@certd/commercial-core": "^1.39.8",
|
||||
"@certd/cv4pve-api-javascript": "^8.4.2",
|
||||
"@certd/jdcloud": "^1.39.7",
|
||||
"@certd/lib-huawei": "^1.39.7",
|
||||
"@certd/lib-k8s": "^1.39.7",
|
||||
"@certd/lib-server": "^1.39.7",
|
||||
"@certd/midway-flyway-js": "^1.39.7",
|
||||
"@certd/pipeline": "^1.39.7",
|
||||
"@certd/plugin-cert": "^1.39.7",
|
||||
"@certd/plugin-lib": "^1.39.7",
|
||||
"@certd/plugin-plus": "^1.39.7",
|
||||
"@certd/plus-core": "^1.39.7",
|
||||
"@certd/jdcloud": "^1.39.8",
|
||||
"@certd/lib-huawei": "^1.39.8",
|
||||
"@certd/lib-k8s": "^1.39.8",
|
||||
"@certd/lib-server": "^1.39.8",
|
||||
"@certd/midway-flyway-js": "^1.39.8",
|
||||
"@certd/pipeline": "^1.39.8",
|
||||
"@certd/plugin-cert": "^1.39.8",
|
||||
"@certd/plugin-lib": "^1.39.8",
|
||||
"@certd/plugin-plus": "^1.39.8",
|
||||
"@certd/plus-core": "^1.39.8",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.185",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.185",
|
||||
|
||||
@@ -44,4 +44,5 @@
|
||||
// export * from './plugin-lib/index.js'
|
||||
// export * from './plugin-plus/index.js'
|
||||
// export * from './plugin-cert/index.js'
|
||||
// export * from './plugin-zenlayer/index.js'
|
||||
// export * from './plugin-zenlayer/index.js'
|
||||
export * from './plugin-dnsmgr/index.js'
|
||||
@@ -156,7 +156,7 @@ export abstract class CertApplyBasePlugin extends CertApplyBaseConvertPlugin {
|
||||
if(maxDays < 2){
|
||||
maxDays = 2;
|
||||
}
|
||||
this.logger.warn(`为避免每次运行都更新证书,更新天数自动减半,调整为${maxDays}`);
|
||||
this.logger.warn(`为避免每次运行都更新证书,更新天数自动减半(即证书最大时长${totalDays}天减半),调整为${maxDays}`);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
144
packages/ui/certd-server/src/plugins/plugin-dnsmgr/access.ts
Normal file
144
packages/ui/certd-server/src/plugins/plugin-dnsmgr/access.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { AccessInput, BaseAccess, IsAccess, Pager, PageRes, PageSearch } from '@certd/pipeline';
|
||||
import { DomainRecord } from '@certd/plugin-lib';
|
||||
|
||||
@IsAccess({
|
||||
name: 'dnsmgr',
|
||||
title: '彩虹DNS',
|
||||
icon: 'clarity:plugin-line',
|
||||
desc: '彩虹DNS管理系统授权',
|
||||
})
|
||||
export class DnsmgrAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: '系统地址',
|
||||
component: {
|
||||
name: "a-input",
|
||||
allowClear: true,
|
||||
placeholder: 'https://dnsmgr.example.com',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
endpoint = '';
|
||||
|
||||
@AccessInput({
|
||||
title: '用户ID',
|
||||
component: {
|
||||
name: "a-input",
|
||||
allowClear: true,
|
||||
placeholder: '123456',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
uid = '';
|
||||
|
||||
@AccessInput({
|
||||
title: 'API密钥',
|
||||
required: true,
|
||||
encrypt: true,
|
||||
})
|
||||
key = '';
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
helper: "点击测试接口是否正常"
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.GetDomainList({});
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async GetDomainList(req: PageSearch): Promise<PageRes<DomainRecord>> {
|
||||
this.ctx.logger.info(`获取域名列表,req:${JSON.stringify(req)}`);
|
||||
const pager = new Pager(req);
|
||||
const resp = await this.doRequest({
|
||||
url: '/api/domain',
|
||||
data: {
|
||||
offset: pager.getOffset(),
|
||||
limit: pager.pageSize,
|
||||
kw: req.searchKey,
|
||||
},
|
||||
});
|
||||
const total = resp?.total || 0;
|
||||
let list = resp?.rows?.map((item: any) => {
|
||||
return {
|
||||
domain: item.name,
|
||||
...item,
|
||||
};
|
||||
});
|
||||
return {
|
||||
total,
|
||||
list,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
async createDnsRecord(domainId: string, record: string, value: string, type: string, domain: string) {
|
||||
this.ctx.logger.info(`创建DNS记录:${record} ${type} ${value}`);
|
||||
const resp = await this.doRequest({
|
||||
url: `/api/record/add/${domainId}`,
|
||||
data: {
|
||||
name: record.replace(`.${domain}`, ''),
|
||||
type,
|
||||
value,
|
||||
line: 'default',
|
||||
ttl: 600,
|
||||
},
|
||||
});
|
||||
return resp;
|
||||
}
|
||||
|
||||
async getDnsRecords(domainId: string, type?: string, name?: string, value?: string) {
|
||||
this.ctx.logger.info(`获取DNS记录列表:domainId=${domainId}, type=${type}, name=${name}`);
|
||||
const resp = await this.doRequest({
|
||||
url: `/api/record/data/${domainId}`,
|
||||
data: {
|
||||
type,
|
||||
subdomain: name,
|
||||
value,
|
||||
},
|
||||
});
|
||||
return resp;
|
||||
}
|
||||
|
||||
async deleteDnsRecord(domainId: string, recordId: string) {
|
||||
this.ctx.logger.info(`删除DNS记录:domainId=${domainId}, recordId=${recordId}`);
|
||||
const resp = await this.doRequest({
|
||||
url: `/api/record/delete/${domainId}`,
|
||||
data: {
|
||||
recordid: recordId,
|
||||
},
|
||||
});
|
||||
return resp;
|
||||
}
|
||||
|
||||
async doRequest(req: { url: string; data?: any }) {
|
||||
const timestamp = Math.floor(Date.now() / 1000);
|
||||
const sign = this.ctx.utils.hash.md5(`${this.uid}${timestamp}${this.key}`);
|
||||
const url = `${this.endpoint}${req.url}`;
|
||||
|
||||
const res = await this.ctx.http.request({
|
||||
url,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
data: {
|
||||
uid: this.uid,
|
||||
timestamp,
|
||||
sign,
|
||||
...req.data,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.code !== undefined && res.code !== 0) {
|
||||
throw new Error(res.msg || '请求失败');
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert';
|
||||
import { DnsmgrAccess } from './access.js';
|
||||
import { PageRes, PageSearch } from '@certd/pipeline';
|
||||
|
||||
type DnsmgrRecord = {
|
||||
domainId: string;
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
@IsDnsProvider({
|
||||
name: 'dnsmgr',
|
||||
title: '彩虹DNS',
|
||||
desc: '彩虹DNS管理系统',
|
||||
icon: 'clarity:plugin-line',
|
||||
accessType: 'dnsmgr',
|
||||
order: 99,
|
||||
})
|
||||
export class DnsmgrDnsProvider extends AbstractDnsProvider<DnsmgrRecord> {
|
||||
access!: DnsmgrAccess;
|
||||
|
||||
async onInstance() {
|
||||
this.access = this.ctx.access as DnsmgrAccess;
|
||||
this.logger.debug('access', this.access);
|
||||
}
|
||||
|
||||
async createRecord(options: CreateRecordOptions): Promise<any> {
|
||||
const { fullRecord, value, type, domain } = options;
|
||||
this.logger.info('添加域名解析:', fullRecord, value, type, domain);
|
||||
|
||||
const domainList = await this.access.GetDomainList({ searchKey: domain });
|
||||
const domainInfo = domainList.list?.find((item: any) => item.name === domain);
|
||||
|
||||
if (!domainInfo) {
|
||||
throw new Error(`未找到域名:${domain}`);
|
||||
}
|
||||
|
||||
const name = fullRecord.replace(`.${domain}`, '');
|
||||
const res = await this.access.createDnsRecord(domainInfo.id, fullRecord, value, type, domain);
|
||||
return { domainId: domainInfo.id, name, value,res };
|
||||
}
|
||||
|
||||
async removeRecord(options: RemoveRecordOptions<DnsmgrRecord>): Promise<void> {
|
||||
const { fullRecord, value } = options.recordReq;
|
||||
const record = options.recordRes;
|
||||
this.logger.info('删除域名解析:', fullRecord, value, record);
|
||||
|
||||
if (record && record.domainId) {
|
||||
const records = await this.access.getDnsRecords(record.domainId, 'TXT', record.name, record.value);
|
||||
if (records && records.rows && records.rows.length > 0) {
|
||||
const recordToDelete = records.rows[0];
|
||||
await this.access.deleteDnsRecord(record.domainId, recordToDelete.RecordId);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.info('删除域名解析成功:', fullRecord, value);
|
||||
}
|
||||
|
||||
async getDomainListPage(req: PageSearch): Promise<PageRes<DomainRecord>> {
|
||||
const res = await this.access.GetDomainList(req);
|
||||
res.list = res.list?.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
domain: item.name,
|
||||
};
|
||||
});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
new DnsmgrDnsProvider();
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './access.js';
|
||||
export * from './dns-provider.js';
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./plugin-deploy-to-cdn.js";
|
||||
export * from "./plugin-deploy-to-blb.js";
|
||||
export * from "./plugin-upload-to-baidu.js";
|
||||
export * from "./plugin-deploy-to-cce.js";
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { utils } from "@certd/basic";
|
||||
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { BaiduAccess } from "../access.js";
|
||||
import { BaiduYunClient } from "../client.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: "DeployCertToBaiduCce",
|
||||
title: "百度云-部署到CCE",
|
||||
icon: "ant-design:cloud-outlined",
|
||||
desc: "部署到百度云CCE集群Ingress等通过Secret管理证书的应用",
|
||||
group: pluginGroups.baidu.key,
|
||||
needPlus: true,
|
||||
input: {},
|
||||
output: {},
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class DeployCertToBaiduCcePlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
@TaskInput({
|
||||
title: "Access授权",
|
||||
helper: "百度云授权AccessKey、SecretKey",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "baidu",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "大区",
|
||||
component: {
|
||||
name: "a-auto-complete",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "bj", label: "北京" },
|
||||
{ value: "gz", label: "广州" },
|
||||
{ value: "su", label: "苏州" },
|
||||
{ value: "bd", label: "保定" },
|
||||
{ value: "fwh", label: "武汉" },
|
||||
{ value: "hkg", label: "香港" },
|
||||
{ value: "yq", label: "阳泉" },
|
||||
{ value: "cd", label: "成都" },
|
||||
{ value: "nj", label: "南京" },
|
||||
],
|
||||
placeholder: "集群所属大区",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
regionId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "集群id",
|
||||
component: {
|
||||
placeholder: "集群id",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
clusterId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "保密字典Id",
|
||||
component: {
|
||||
placeholder: "保密字典Id",
|
||||
},
|
||||
helper: "原本存储证书的secret的name",
|
||||
required: true,
|
||||
})
|
||||
secretName!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: "命名空间",
|
||||
value: "default",
|
||||
component: {
|
||||
placeholder: "命名空间",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
namespace = "default";
|
||||
|
||||
@TaskInput({
|
||||
title: "Kubeconfig类型",
|
||||
value: "public",
|
||||
component: {
|
||||
name: "a-auto-complete",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "vpc", label: "VPC私网IP (BLB VPCIP)" },
|
||||
{ value: "public", label: "公网IP (BLB EIP)" },
|
||||
],
|
||||
placeholder: "选择集群连接端点类型",
|
||||
},
|
||||
helper: "VPC类型使用私网IP连接,需要certd运行在同一网络环境;public类型使用公网IP连接",
|
||||
required: true,
|
||||
})
|
||||
kubeconfigType!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "忽略证书校验",
|
||||
required: false,
|
||||
helper: "是否忽略证书校验",
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "checked",
|
||||
},
|
||||
})
|
||||
skipTLSVerify!: boolean;
|
||||
|
||||
@TaskInput({
|
||||
title: "Secret自动创建",
|
||||
helper: "如果Secret不存在,则创建,百度云的自动创建secret有问题",
|
||||
value: false,
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "checked",
|
||||
},
|
||||
})
|
||||
createOnNotFound: boolean;
|
||||
|
||||
K8sClient: any;
|
||||
async onInstance() {
|
||||
const sdk = await import("@certd/lib-k8s");
|
||||
this.K8sClient = sdk.K8sClient;
|
||||
}
|
||||
async execute(): Promise<void> {
|
||||
this.logger.info("开始部署证书到百度云CCE");
|
||||
const { regionId, clusterId, kubeconfigType, cert } = this;
|
||||
const access = (await this.getAccess(this.accessId)) as BaiduAccess;
|
||||
const client = new BaiduYunClient({
|
||||
access,
|
||||
logger: this.logger,
|
||||
http: this.ctx.http,
|
||||
});
|
||||
const kubeConfigStr = await this.getKubeConfig(client, clusterId, regionId, kubeconfigType);
|
||||
|
||||
this.logger.info("kubeconfig已成功获取");
|
||||
const k8sClient = new this.K8sClient({
|
||||
kubeConfigStr,
|
||||
logger: this.logger,
|
||||
skipTLSVerify: this.skipTLSVerify,
|
||||
});
|
||||
await this.patchCertSecret({ cert, k8sClient });
|
||||
|
||||
await utils.sleep(5000);
|
||||
|
||||
try {
|
||||
await this.restartIngress({ k8sClient });
|
||||
} catch (e) {
|
||||
this.logger.warn(`重启ingress失败:${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async restartIngress(options: { k8sClient: any }) {
|
||||
const { k8sClient } = options;
|
||||
const { namespace } = this;
|
||||
|
||||
const body = {
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix("certd"),
|
||||
},
|
||||
},
|
||||
};
|
||||
const ingressList = await k8sClient.getIngressList({ namespace });
|
||||
this.logger.info("ingressList:", JSON.stringify(ingressList));
|
||||
if (!ingressList || !ingressList.items) {
|
||||
return;
|
||||
}
|
||||
const ingressNames = ingressList.items
|
||||
.filter((item: any) => {
|
||||
if (!item.spec.tls) {
|
||||
return false;
|
||||
}
|
||||
for (const tls of item.spec.tls) {
|
||||
if (tls.secretName === this.secretName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.map((item: any) => {
|
||||
return item.metadata.name;
|
||||
});
|
||||
for (const ingress of ingressNames) {
|
||||
await k8sClient.patchIngress({ namespace, ingressName: ingress, body, createOnNotFound: this.createOnNotFound });
|
||||
this.logger.info(`ingress已重启:${ingress}`);
|
||||
}
|
||||
}
|
||||
|
||||
async patchCertSecret(options: { cert: CertInfo; k8sClient: any }) {
|
||||
const { cert, k8sClient } = options;
|
||||
const crt = cert.crt;
|
||||
const key = cert.key;
|
||||
const crtBase64 = Buffer.from(crt).toString("base64");
|
||||
const keyBase64 = Buffer.from(key).toString("base64");
|
||||
|
||||
const { namespace, secretName } = this;
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
"tls.crt": crtBase64,
|
||||
"tls.key": keyBase64,
|
||||
},
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix("certd"),
|
||||
},
|
||||
},
|
||||
};
|
||||
let secretNames: any = secretName;
|
||||
if (typeof secretName === "string") {
|
||||
secretNames = [secretName];
|
||||
}
|
||||
for (const secret of secretNames) {
|
||||
await k8sClient.patchSecret({ namespace, secretName: secret, body ,createOnNotFound: this.createOnNotFound});
|
||||
this.logger.info(`cert secret已更新: ${secret}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getKubeConfig(client: BaiduYunClient, clusterId: string, regionId: string, kubeconfigType: string) {
|
||||
const res = await client.doRequest({
|
||||
host: `cce.${regionId}.baidubce.com`,
|
||||
uri: `/v2/kubeconfig/${clusterId}/${kubeconfigType}`,
|
||||
method: "get",
|
||||
});
|
||||
return res.kubeConfig;
|
||||
}
|
||||
}
|
||||
|
||||
new DeployCertToBaiduCcePlugin();
|
||||
@@ -62,6 +62,21 @@ export class K8sApplyPlugin extends AbstractPlusTaskPlugin {
|
||||
// })
|
||||
// namespace!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "应用策略",
|
||||
helper: "选择使用apply(创建或更新)还是patch(补丁更新)",
|
||||
component: {
|
||||
name: "a-select",
|
||||
options: [
|
||||
{ label: "apply(创建)", value: "apply" },
|
||||
{ label: "patch(更新)", value: "patch" },
|
||||
],
|
||||
},
|
||||
value: "apply",
|
||||
required: true,
|
||||
})
|
||||
strategy!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "yaml",
|
||||
required: true,
|
||||
@@ -112,8 +127,13 @@ export class K8sApplyPlugin extends AbstractPlusTaskPlugin {
|
||||
try {
|
||||
// this.logger.info("apply yaml:", compiledYaml);
|
||||
// this.logger.info("apply yamlDoc:", JSON.stringify(doc));
|
||||
const res = await client.apply(compiledYaml);
|
||||
this.logger.info("apply result:", res);
|
||||
if (this.strategy === "apply") {
|
||||
await client.apply(compiledYaml);
|
||||
this.logger.info("apply success");
|
||||
} else {
|
||||
await client.applyPatch(compiledYaml);
|
||||
this.logger.info("patch success");
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.response?.body) {
|
||||
throw new Error(JSON.stringify(e.response.body));
|
||||
|
||||
148
packages/ui/certd-server/src/plugins/plugin-spaceship/access.ts
Normal file
148
packages/ui/certd-server/src/plugins/plugin-spaceship/access.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { IsAccess, AccessInput, BaseAccess, PageSearch } from "@certd/pipeline";
|
||||
|
||||
@IsAccess({
|
||||
name: "spaceship",
|
||||
title: "Spaceship.com 授权",
|
||||
icon: "clarity:plugin-line",
|
||||
desc: "Spaceship.com API 授权插件"
|
||||
})
|
||||
export class SpaceshipAccess extends BaseAccess {
|
||||
|
||||
@AccessInput({
|
||||
title: "API Key",
|
||||
component: {
|
||||
placeholder: "请输入 API Key"
|
||||
},
|
||||
required: true,
|
||||
encrypt: true,
|
||||
helper: "前往 [获取 API Key](https://www.spaceship.com/application/api-manager/)"
|
||||
})
|
||||
apiKey = "";
|
||||
|
||||
@AccessInput({
|
||||
title: "API Secret",
|
||||
component: {
|
||||
name: "a-input-password",
|
||||
vModel: "value",
|
||||
placeholder: "请输入 API Secret"
|
||||
},
|
||||
required: true,
|
||||
encrypt: true
|
||||
})
|
||||
apiSecret = "";
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
helper: "测试 API 连接是否正常"
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.GetDomainList({});
|
||||
return "ok";
|
||||
}
|
||||
|
||||
async doRequest(options: {
|
||||
url: string;
|
||||
method: 'GET' | 'POST' | 'DELETE';
|
||||
params?: any;
|
||||
data?: any;
|
||||
}) {
|
||||
const headers = {
|
||||
"X-Api-Key": this.apiKey,
|
||||
"X-Api-Secret": this.apiSecret
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await this.ctx.http.request({
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
headers,
|
||||
params: options.params,
|
||||
data: options.data
|
||||
});
|
||||
return res;
|
||||
} catch (error: any) {
|
||||
const errorMsg = [];
|
||||
const status = error.status || error.response?.status;
|
||||
if (error.response) {
|
||||
const headers = error.response.headers;
|
||||
const data = error.response.data;
|
||||
|
||||
errorMsg.push(`API 请求失败: ${status}`);
|
||||
|
||||
if (headers['spaceship-error-code']) {
|
||||
errorMsg.push(`错误代码: ${headers['spaceship-error-code']}`);
|
||||
}
|
||||
|
||||
if (headers['spaceship-operation-id']) {
|
||||
errorMsg.push(`操作ID: ${headers['spaceship-operation-id']}`);
|
||||
}
|
||||
|
||||
if (data && data.detail) {
|
||||
errorMsg.push(`错误详情: ${data.detail}`);
|
||||
}
|
||||
|
||||
this.ctx.logger.error(`Spaceship API 错误: ${errorMsg.join(' | ')}`);
|
||||
} else if (error.request) {
|
||||
errorMsg.push(`请求发送失败: ${error.message}`);
|
||||
this.ctx.logger.error(`Spaceship API 请求发送失败: ${error.message}`);
|
||||
} else {
|
||||
errorMsg.push(`请求配置错误: ${error.message}`);
|
||||
this.ctx.logger.error(`Spaceship API 请求配置错误: ${error.message}`);
|
||||
}
|
||||
|
||||
const error2 = new Error(errorMsg.join(' | '));
|
||||
//@ts-ignore
|
||||
error2.status = status;
|
||||
throw error2;
|
||||
}
|
||||
}
|
||||
|
||||
async GetDomainList(req: PageSearch) {
|
||||
const take = req.pageSize || 100;
|
||||
const skip = ((req.pageNo || 1) - 1) * take;
|
||||
|
||||
const res = await this.doRequest({
|
||||
url: "https://spaceship.dev/api/v1/domains",
|
||||
method: "GET",
|
||||
params: {
|
||||
take,
|
||||
skip
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
total: res.total || 0,
|
||||
list: res.items || []
|
||||
};
|
||||
}
|
||||
|
||||
async getDomainInfo(domain: string) {
|
||||
try {
|
||||
const res = await this.doRequest({
|
||||
url: `https://spaceship.dev/api/v1/domains/${domain}`,
|
||||
method: "GET"
|
||||
});
|
||||
return res;
|
||||
} catch (error: any) {
|
||||
if (error.status === 404) {
|
||||
throw new Error(`域名 ${domain} 不存在于当前账号中`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
getCacheKey() {
|
||||
const hashStr = this.apiKey + this.apiSecret;
|
||||
const hashCode = this.ctx.utils.hash.sha256(hashStr);
|
||||
return `spaceship-${hashCode}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new SpaceshipAccess();
|
||||
@@ -0,0 +1,95 @@
|
||||
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
|
||||
import { SpaceshipAccess } from "./access.js";
|
||||
import { PageRes, PageSearch } from "@certd/pipeline";
|
||||
|
||||
export type SpaceshipRecord = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
content: string;
|
||||
domainId: string;
|
||||
};
|
||||
|
||||
@IsDnsProvider({
|
||||
name: "spaceship",
|
||||
title: "Spaceship",
|
||||
desc: "Spaceship 域名解析",
|
||||
icon: "clarity:plugin-line",
|
||||
accessType: "spaceship",
|
||||
order: 99
|
||||
})
|
||||
export class SpaceshipProvider extends AbstractDnsProvider<SpaceshipRecord> {
|
||||
access!: SpaceshipAccess;
|
||||
|
||||
async onInstance() {
|
||||
this.access = this.ctx.access as SpaceshipAccess;
|
||||
}
|
||||
|
||||
async createRecord(options: CreateRecordOptions): Promise<SpaceshipRecord> {
|
||||
const { fullRecord, hostRecord, value, type, domain } = options;
|
||||
this.logger.info("添加域名解析:", fullRecord, value, type, domain);
|
||||
|
||||
await this.access.getDomainInfo(domain);
|
||||
|
||||
const recordRes = await this.access.doRequest({
|
||||
url: `https://spaceship.dev/api/v1/domains/${domain}/records`,
|
||||
method: "POST",
|
||||
data: {
|
||||
force: false,
|
||||
items: [
|
||||
{
|
||||
type: type,
|
||||
value: value,
|
||||
name: hostRecord,
|
||||
ttl: 300
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id: recordRes.items[0].id,
|
||||
name: hostRecord,
|
||||
type: type,
|
||||
content: value,
|
||||
domainId: domain
|
||||
};
|
||||
}
|
||||
|
||||
async removeRecord(options: RemoveRecordOptions<SpaceshipRecord>): Promise<void> {
|
||||
const recordRes = options.recordRes;
|
||||
this.logger.info("删除域名解析:", recordRes);
|
||||
|
||||
await this.access.doRequest({
|
||||
url: `https://spaceship.dev/api/v1/domains/${recordRes.domainId}/records`,
|
||||
method: "DELETE",
|
||||
data: {
|
||||
Records: [
|
||||
{
|
||||
type: recordRes.type,
|
||||
value: recordRes.content,
|
||||
name: recordRes.name
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.info("删除域名解析成功:", recordRes.name);
|
||||
}
|
||||
|
||||
async getDomainListPage(req: PageSearch): Promise<PageRes<DomainRecord>> {
|
||||
const res = await this.access.GetDomainList(req);
|
||||
|
||||
const list = res.list.map((item: any) => ({
|
||||
domain: item.name,
|
||||
id: item.name
|
||||
}));
|
||||
|
||||
return {
|
||||
total: res.total || 0,
|
||||
list: list || []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
new SpaceshipProvider();
|
||||
@@ -0,0 +1,2 @@
|
||||
import "./access.js";
|
||||
import "./dns-provider.js";
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import dayjs from 'dayjs';
|
||||
import { TencentAccess } from '../../../plugin-lib/tencent/index.js';
|
||||
import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
import { CertApplyPluginNames, CertInfo } from '@certd/plugin-cert';
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToTencentCLB',
|
||||
title: '腾讯云-部署到CLB',
|
||||
@@ -15,6 +15,31 @@ import { CertApplyPluginNames} from '@certd/plugin-cert';
|
||||
},
|
||||
})
|
||||
export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames, 'UploadCertToTencent'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: string | CertInfo;
|
||||
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access提供者',
|
||||
helper: 'access授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'tencent',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '大区',
|
||||
component: {
|
||||
@@ -40,20 +65,18 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
{ value: 'na-siliconvalley' },
|
||||
{ value: 'na-toronto' },
|
||||
{ value: 'sa-saopaulo' },
|
||||
{ value: 'ap-taipei' },
|
||||
],
|
||||
helper: '如果列表中没有,您可以手动输入',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '证书名称前缀',
|
||||
})
|
||||
certName!: string;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: '负载均衡ID',
|
||||
helper: '如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)',
|
||||
required: true,
|
||||
})
|
||||
loadBalancerId!: string;
|
||||
@@ -78,26 +101,10 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
domain!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: [...CertApplyPluginNames],
|
||||
},
|
||||
required: true,
|
||||
title: '证书名称前缀',
|
||||
})
|
||||
cert!: any;
|
||||
certName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access提供者',
|
||||
helper: 'access授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'tencent',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
client: any;
|
||||
async onInstance() {
|
||||
@@ -234,12 +241,23 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
return name + '-' + dayjs().format('YYYYMMDD-HHmmss');
|
||||
}
|
||||
buildProps() {
|
||||
const certId = this.cert as string;
|
||||
const certInfo = this.cert as CertInfo;
|
||||
if (typeof this.cert === 'string') {
|
||||
return {
|
||||
Certificate: {
|
||||
CertId: certId,
|
||||
},
|
||||
LoadBalancerId: this.loadBalancerId,
|
||||
ListenerId: this.listenerId,
|
||||
};
|
||||
}
|
||||
return {
|
||||
Certificate: {
|
||||
SSLMode: 'UNIDIRECTIONAL', // 单向认证
|
||||
CertName: this.appendTimeSuffix(this.certName || this.cert.domain),
|
||||
CertKey: this.cert.key,
|
||||
CertContent: this.cert.crt,
|
||||
CertName: this.appendTimeSuffix(this.certName || "certd"),
|
||||
CertKey: certInfo.key,
|
||||
CertContent: certInfo.crt,
|
||||
},
|
||||
LoadBalancerId: this.loadBalancerId,
|
||||
ListenerId: this.listenerId,
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:07
|
||||
23:58
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:28
|
||||
00:29
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
// 这样就可以对 `this` 上的数据属性进行更严格的推断`
|
||||
"noImplicitAny": true,
|
||||
"allowJs": true,
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strictNullChecks" :false,
|
||||
"inlineSourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user