Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions .agents/skills/hapsign-hap-deploy/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: hapsign-hap-deploy
description: Authenticate, sign, install, or deploy unsigned and signed HarmonyOS HAPs on an explicitly selected connected device through the hapsign CLI. Use for HAP deployment; not for building HAPs, emulator-only workflows, or manual DevEco/HDC signing.
description: Install or deploy authorized HarmonyOS HAPs on an explicitly selected connected device through the hapsign CLI. Use for device deployment; use hapsign-signing for sign-only or signing-troubleshooting workflows.
---

# HapSign HAP Deploy
Expand All @@ -10,29 +10,48 @@ authentication, token caching, device-bound Profiles, signing, HDC installation,
and post-install bundle checks. Do not recreate those steps with DevEco, raw HDC,
or skill-local scripts.

## Commands
## Safe deployment workflow

Always request JSON and pass an explicit HDC serial:
Use the CLI's read-only checks before authentication or deployment:

```bash
hapsign doctor --json
hapsign inspect --hap <hap> --json
hapsign devices list --connected-only --json
hapsign auth status --json
hapsign auth --json
hapsign sign --hap <unsigned.hap> --serial <serial> --json
hapsign install --hap <signed.hap> --serial <serial> --json
hapsign deploy --hap <hap> --serial <serial> --json
```

When deployment needs a Real Profile/system_basic, pass `--enable-capability`
to both `inspect` and `deploy` so cache compatibility is evaluated consistently.

- Require `capabilities.device.ok`; also require `capabilities.signing.ok` for
an unsigned HAP.
- If `migration_warnings` contains an item with `destructive=true` and
`requires_user_decision=true`, explain its impact and remediation and stop
for the user's choice. Do not silently refresh or migrate signing materials.
- Honor a serial supplied by the user. Otherwise select the sole
`physical_candidate=true` target; ask the user if zero or multiple physical
candidates remain. Do not select `likely_emulator=true` unless requested.
- Use `sign` for signing only, `install` for an already signed HAP, and `deploy`
for end-to-end signing and installation. `deploy` also accepts signed HAPs.
- Check `auth status` before an operation that may need login. If no current cache
exists and the request does not already authorize account authentication, tell
the user that browser authorization is required before running `auth`.

Then use JSON and the explicit HDC serial. Installing an already signed HAP does
not require Huawei authentication:

```bash
hapsign install --hap <signed.hap> --serial <serial> --json
hapsign deploy --hap <hap> --serial <serial> --json
```

- Use `install` for an already signed HAP and `deploy` for end-to-end signing
and installation. `deploy` also accepts signed HAPs.
- For an unsigned HAP, `deploy` can perform authentication itself. If no current
cache exists and the request does not already authorize account authentication,
tell the user that browser authorization will be required before running it.
Use a separate `auth status`/`auth` step only when the user wants authentication
prepared independently; never authenticate for a signed-only `install`.

Treat success as exit code `0` plus JSON `ok=true`. Parse stdout as JSON and treat
stderr as diagnostic logs. On failure, report `error.type`, `error.message`, and
the exit code; do not fall back to manual signing or raw HDC installation. Never
print or copy tokens, passwords, signing keys, Profiles, or device UDIDs.
When `--enable-capability` was requested, report `capability_fallback=true` as a
successful debug install whose effective Profile is still normal, not as a
successful system_basic deployment.
168 changes: 168 additions & 0 deletions .agents/skills/hapsign-signing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
name: hapsign-signing
description: Inspect, debug-sign, and optionally install authorized HarmonyOS .hap packages with HapSign on Windows, Linux, or macOS using machine-readable JSON and user-assisted Huawei authorization. Use for local HAP debug signing and troubleshooting, not production AppGallery signing or generic OS code signing.
---

# HapSign HAP signing

Use HapSign only for authorized local HarmonyOS development and debugging. It
creates Huawei debug signing materials; it does not replace AppGallery
production-release signing.

## Locate and identify the CLI

Prefer, in order:

1. The path in `HAPSIGN_CLI`.
2. The complete portable package in the current HapSign repository:
`dist/HapSign/hapsign-cli.exe` on Windows or
`dist/HapSign/hapsign-cli` on Linux/macOS.
3. A `hapsign` source-install command on `PATH`.
4. A complete portable folder supplied by the user.

Do not use a copied standalone executable without its sibling `resources/`.
Resolve the CLI, input HAP, and output HAP to absolute paths. For portable
builds, run with the CLI parent directory as the working directory so older
builds also keep caches beside the application. If no usable CLI exists, report
the paths checked and ask where HapSign is installed.

Before processing a HAP, run:

```text
<cli> --version
<cli> doctor --json
```

In PowerShell invoke a quoted executable with `&`. On POSIX, invoke the
executable directly.

Interpret doctor capabilities separately:

- `capabilities.signing.ok` is required to sign an unsigned HAP.
- `capabilities.device.ok` is required for installation and for obtaining a
first-time Profile UDID from a connected device.
- Top-level `ok` may be false while sign-only remains possible with valid
cached signing materials or a trusted explicit UDID.
- Read `paths.state_dir` and `paths.output_dir`; do not infer storage from the
process working directory. Report relevant entries from `breaking_changes`
when upgrading an existing installation.

## Safe agent workflow

1. Inspect the input without logging in, connecting a device, or changing it:

```text
<cli> inspect --hap <absolute-input.hap> --json
```

If the requested signing mode needs a Real Profile/system_basic, include
`--enable-capability` in both this inspection and the later `sign` or
`deploy` command. Cache compatibility is evaluated against that mode.

Read `migration_warnings` before continuing. If a warning has
`destructive: true` and `requires_user_decision: true`, explain its impact
and remediation, then wait for the user's choice. Never silently accept a
destructive migration.

For `HAPSIGN-BREAKING-001`, inspect `reasons`. A sole
`capability_mode_mismatch` can be resolved by consistently matching the
cached mode, or by backing up `paths.work_dir` and accepting a refresh when
the user intends to switch modes. Offer metadata migration only when the
warning reports `migratable: true` and the user confirms the legacy Profile
type; then run one of:

```text
<cli> migrate-cache --hap <absolute-input.hap> \
--state-dir <paths.state_dir> --profile-type normal --json
<cli> migrate-cache --hap <absolute-input.hap> \
--state-dir <paths.state_dir> --profile-type system-basic --json
```

Do not guess the legacy Profile type. The migration command only updates
metadata and legacy relative material paths, keeps a backup, and must return
`command: migrate-cache` and `ok: true` before reuse. A stale or incomplete
cache cannot be migrated; back it up and allow refresh instead.

2. For a signing request, default to sign-only. Choose a new absolute `.hap`
output path and verify that it does not already exist:

```text
<cli> sign --hap <absolute-input.hap> \
--output <absolute-output.hap> --browser system_controlled --json
```

`system_controlled` uses an isolated Edge/Chrome context without the user's
cookies or saved passwords and grants the authorization page local callback
access. Use `system` only when the user explicitly prefers their normal
browser profile or controlled launch is unavailable; disclose that cached
SSO state, extensions, and local-network permissions can change the flow.
Use `playwright` only when bundled Chromium is explicitly preferred.

If persistent locations matter, pass absolute `--state-dir` and either an
exact `--output` or `--output-dir`. CLI flags override
`HAPSIGN_SIGNING_DIR` / `HAPSIGN_SIGNED_HAPS_DIR`, which override the
application defaults. Never place signing state in shared or cloud-synced
storage.

3. Never add `--overwrite-output` unless the user explicitly authorizes
replacing that exact file. Add `--device-udid` only for a trusted,
user-authorized 64-character UDID. Add `--enable-capability` only when the
user requests a Real Profile/system_basic capability or the task clearly
requires it.

4. If authorization opens, tell the user to complete login, CAPTCHA, consent,
and two-factor verification manually, then wait for the process. Never
request, read, store, type, or automate credentials, CAPTCHA, one-time codes,
consent clicks, or tokens.

5. Treat a nonzero exit code or JSON `ok: false` as failure. On success, read
`signed_hap` from JSON instead of guessing a path, then verify it:

```text
<cli> inspect --hap <signed_hap> --json
```

Report success only when the verification returns `signed: true`. For an
already-signed input, accept the `signed_hap` path returned by the CLI even
though no cryptographic signing step ran; do not infer it from the input.
When a Real Profile was requested, also inspect `capability_fallback` and
`capability_mode`. A fallback result is a valid debug signature but did not
satisfy system_basic; disclose that limitation instead of reporting the
requested capability as successful.

6. Install only when the user explicitly requests device installation. Use
`deploy --hap <input> --serial <serial>` for signing plus installation, or
`install --hap <signed_hap> --serial <serial>` for an already signed HAP.
Require a connected authorized device and report the returned `installed`
value. Signing permission alone does not authorize installation.

## Authorization diagnostics

Keep logs at a nonsensitive level and use stage markers:

- No `[callback]` entry: the browser did not reach the loopback callback;
check browser mode and local-network access.
- Callback POST/GET without `授权回调校验成功`: inspect the redacted CSRF or
parameter error.
- Callback validation succeeded: browser spinning or subsequent
`net::ERR_ABORTED` requests are usually page shutdown after the callback;
investigate token exchange or later pipeline stages instead.
- A Windows DPAPI cache decryption failure should trigger a fresh user login.
Linux/macOS token caches are plaintext files restricted to mode `0o600`; do
not place them in shared or cloud-synced storage. Do not delete signing state
unless the user explicitly requests cleanup.

When diagnosing a GUI run, first identify the actual executable and its log
directory; do not assume source CLI, portable CLI, and GUI share a directory in
older builds.

## Sensitive data and boundaries

- `signing_files/` contains private keys, certificates, Profiles, and login
cache. Never print, commit, upload, or place it in untrusted/shared storage.
- Keep sensitive logging disabled. Do not expose full UDIDs, account identifiers,
tokens, passwords, private-key material, or complete authentication payloads.
- Network access and a verified Huawei developer account are required when
cached authorization/signing materials are unavailable.
- This skill is for HAP debug signing. Route EXE/MSI signing, certificate
issuance, and production release signing elsewhere.
7 changes: 7 additions & 0 deletions .agents/skills/hapsign-signing/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface:
display_name: "HapSign HAP Signing"
short_description: "Inspect, debug-sign, and install HarmonyOS HAPs"
default_prompt: "Use $hapsign-signing to inspect and debug-sign this authorized HarmonyOS HAP."

policy:
allow_implicit_invocation: true
6 changes: 4 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ body:
options:
- Windows 精简便携包
- Windows Chromium 兼容包
- Python 源码 GUI
- Python CLI
- Linux 便携包
- macOS 便携包
- Python 源码 GUI(Windows/Linux/macOS)
- Python CLI(Windows/Linux/macOS)
- 其他
validations:
required: true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
python-version: ["3.11", "3.13"]
os: [windows-latest, macos-latest, ubuntu-latest]
python-version: ["3.11", "3.12", "3.13"]

runs-on: ${{ matrix.os }}

Expand Down
45 changes: 40 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,38 @@

## Unreleased

### Breaking changes

- `HAPSIGN-BREAKING-001`:旧签名缓存缺少或切换能力模式、包名不匹配或设备 UDID
无效时会执行一次性材料刷新;能力模式可通过一致使用 `--enable-capability` 匹配,
只有其余一致性校验通过时,才可显式运行
`migrate-cache --profile-type normal|system-basic` 保留缓存。
- `HAPSIGN-BREAKING-002`:CLI 默认浏览器从普通系统 Profile 改为隔离的
`system_controlled`;可用 `--browser` 或 `HAPSIGN_BROWSER` 配置。
- `HAPSIGN-BREAKING-003`:CLI 默认状态/产物从 PR #5 的 `~/.hapsign`(更早版本为
进程工作目录)改到应用目录;可用 `--state-dir`、`--output-dir`、
`HAPSIGN_SIGNING_DIR` 和 `HAPSIGN_SIGNED_HAPS_DIR` 恢复原路径;`inspect` 会检测
可复用的 PR #5 旧状态,并在发现旧签名材料时阻止 agent 静默刷新材料。
- `HAPSIGN-BREAKING-004`:面向人的 CLI 输出不再作为脚本协议;自动化应使用 `--json`。
- `HAPSIGN-BREAKING-005`:CLI 改为显式子命令接口;旧的扁平参数调用需要按迁移表整改。
完整影响、检测方式与整改命令见 [迁移指南](docs/MIGRATIONS.md)。

### Added

- 新增面向 Agent 的 `auth`、`devices list`、`sign`、`install`、`deploy` CLI
子命令;支持单行 JSON stdout、stderr 日志、明确退出码与输入校验。
- CLI 支持显式 HDC `--serial`、真机/模拟器候选标记、签名与安装分离,以及安装后
`bm dump` 校验;Token 可跨目标设备复用,Profile 缓存按 UDID 隔离。
- CLI 默认状态目录改为跨平台用户主目录 `~/.hapsign`,Windows 对应
`%USERPROFILE%\.hapsign`,不再受 Agent 当前工作目录影响。
- Linux 源码命令行、CI、DevEco/JAVA_HOME/PATH 工具发现,以及锁定并校验的
OpenHarmony 6.1 + Temurin 21 Linux x64 便携工具链准备流程。
- Agent 友好的 `doctor`、`inspect`、`migrate-cache`、`--json`、显式 UDID 和
精确输出路径;仅签名可复用缓存 Profile 而不连接设备,便携包同时提供独立的
`hapsign-cli[.exe]` 控制台程序。
- 机器可读的兼容性变更目录、按 HAP 检测的迁移警告,以及带备份的旧缓存显式迁移命令。
- 仓库级 `.agents/skills/hapsign-signing` 全平台 Codex 技能,包含受控浏览器授权、
能力判定、签名后复检、输出保护和脱敏回调诊断流程。
- Linux HDC server 归属探测在缺少 `lsof` 时回退到 `/proc`,进程启动时间读取不受
`ps` 输出语言影响。
- macOS 支持:按平台解析 DevEco JBR / hap-sign-tool / hdc 路径,可用 `hapsign` 命令行签名安装。
- 可安装的 `hapsign` 命令和标准 Python 项目元数据。
- Ruff、pytest、覆盖率、pre-commit 和 Windows CI 配置。
Expand Down Expand Up @@ -56,9 +80,10 @@

### Changed

- CLI 现在必须显式使用 `auth`、`devices`、`sign`、`install` 或 `deploy`
子命令,并为设备相关命令传入非空 `--serial`;旧的 `hapsign --hap ...`
调用方式不再兼容。
- CLI 现在必须显式使用 `doctor`、`inspect`、`migrate-cache`、`auth`、`devices`、
`sign`、`install` 或 `deploy` 子命令。`deploy`/`install` 必须传入非空
`--serial`;`sign` 可使用 `--serial`、可信的显式 `--device-udid`,或复用兼容的
缓存材料。旧的 `hapsign --hap ...` 调用方式不再兼容。

### Fixed

Expand All @@ -67,6 +92,16 @@
输出误报为空设备列表。
- CLI 不再把缺少 HDC 可执行文件归类为输入错误;`devices`、`install` 等运行时
HDC 失败现在返回 `operation_failed` 和退出码 1。
- CLI 默认使用隔离的 `system_controlled` 浏览器,并把签名缓存与默认输出绑定到应用
目录/配置,避免复用普通浏览器 Profile 或因调用工作目录不同而产生多份缓存。
- 修复 CLI 初始化失败时把 `sign-install` 误报成 `sign`;基础安装现在声明默认受控
浏览器所需的 Playwright 运行时依赖;JSON 协议使用 ASCII 转义,避免 Windows
本地代码页导致 agent 无法解码中文错误。
- 签名材料缓存会校验包名、能力模式、已知设备 UDID 和材料文件类型,避免跨设备或
跨 Profile 模式误用;显式输出的默认不覆盖门禁也覆盖并发发布竞争。
- 缓存分别记录请求与实际能力模式,Real Profile 回退到 Test Profile 后可稳定复用;
CLI JSON 会显式返回实际模式及 `capability_fallback`,避免 agent 误报 system_basic。
- 输入已经签名时,`--output` 仍会按不覆盖策略原子发布到指定路径,不再静默忽略。
- HTTP 客户端正确发送 `User-Agent` / `Accept-Language` 请求头。
- Token 缓存缺少 `jwt_token` 时不再复用,避免后续刷新失败。
- 设备注册将业务层重复错误码视为成功,并保留 HTTP 错误信息中的兼容判定。
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Profile、设备 UDID 或签名后的 HAP 加入仓库。

## 开发环境

项目要求 Windows 或 macOS,以及 Python 3.11 或更高版本。创建并激活虚拟环境后安装开发依赖:
项目支持 Windows、Linux 和 macOS,要求 Python 3.11 或更高版本。创建并激活
虚拟环境后安装开发依赖:

```bash
python -m pip install -r requirements-dev.txt
Expand Down
Loading
Loading