mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
fix(images): minimize ql3 runtime base
This commit is contained in:
@@ -4922,9 +4922,9 @@
|
||||
timeline 1→2、fencing、`pg_rewind` 只读同步重入、双 fresh replicas 与总 gate,Docker HA 资源零残留;本机 OCI
|
||||
attested build 仍因 BuildKit SBOM scanner 网络超时未形成 live clean,GitHub-hosted 六矩阵及真实 GHCR 记录待取得;
|
||||
|
||||
- D-237/ADR-0254 已补齐三镜像的 base/OS high-critical 漏洞发布门,并修复 control/admin 仍可用
|
||||
`ARG NODE_IMAGE` 覆盖基础镜像的架构缺陷。control/admin/local build+runtime 统一固定 Node 24.18.0 Bookworm
|
||||
multiarch digest;CI 复用六个 native build,release 在 publish 前另以只读六矩阵构建并用 Trivy 0.70.0 扫描
|
||||
- D-237/ADR-0254 已补齐五镜像的 base/OS high-critical 漏洞发布门,并修复 control/admin 仍可用
|
||||
`ARG NODE_IMAGE` 覆盖基础镜像的架构缺陷。四个 Dockerfile 的 build stage 固定 Node 24.18.0 Bookworm digest,
|
||||
runtime stage 固定更小的 Node 24.18.0 Alpine 3.23 multiarch digest;CI/release 对五镜像双架构十个 native build 执行 Trivy 0.70.0
|
||||
OS-only HIGH/CRITICAL,unfixed 不忽略、scanner cache 关闭。Action 固定事故后 v0.36.0 完整 commit;central
|
||||
exact-shape policy 当前零例外,任何例外必须绑定 CVE、OS purl、image、owner、ticket、理由且最长 30 天。
|
||||
policy 8/8、image release 34/34、Cluster deployment 31/31;不增 package、runtime dependency 或设备常驻成本。
|
||||
@@ -5594,7 +5594,7 @@
|
||||
| D-234 | Worker management 客户端 CA 轮换必须由 caller-driven 三阶段证据证明,而不能只依赖提交态摘要或最终 rollout 截图。old、overlap、new 每阶段都读取相同 endpoint/server trust/inspect command 下的独立 old/new client identity,服务端 TLS trust CA 与客户端证书 issuer CA 必须显式分离;service-side trust 集合精确为 old、old+new、new,且每个 active issuer 恰有一份当前 CRL,真实访问矩阵固定为 old `[200,200,401]`、new `[401,200,200]`。collector 只能 get exact Deployment/list selected Pods;每阶段必须观察同一 Deployment UID、递增 generation、唯一 resourceVersion、两个跨 Node Ready/tokenless Pod、CA/CRL 摘要注解与相邻世代完整 Pod UID 替换。old/overlap state 和最终报告用 canonical `0600` no-replace 摘要链,最终报告再绑定 D-229 ceremony 与 D-230 durable audit,禁止原始证书/CA/CRL/JWT/key/Kube material/Secret/DSN/Pod/Node identity;D-232 同 CA 单证书吊销保持独立。不得新增 package、依赖、migration、controller、watcher、timer、sidecar、listener、Pool 或连接,Edge/Standalone/Worker 零稳态成本 | Accepted(ADR-0250:三阶段 runner/auditor 定向 8/8,覆盖 exact trust/access/CRL/三代六 Pod happy path、overlap 缺 old CA、generation 未变、Pod UID 复用、collector Secret read 扩权、ceremony identity 漂移、false/widened/sensitive/malformed report 与 exact CLI;顶层 evidence/audit 命令和完整运维 runbook 已落地。workspace package 与第三方依赖不变;生产外部 PKI/IdP/ingress 多节点联合报告待采集) | 只看 final 401/200 无法证明 overlap 可用、全部副本加载相同 trust 或旧 Pod 已退役;把 server CA 当 client issuer 会拒绝正确的双 PKI 拓扑;复用 D-232 会混淆证书吊销与 CA rollover;让 runner 自改 Secret/Deployment 会合并变更与证明 authority。三个只读 observation、摘要链、真实双 client 请求和独立离线重判提供最小完整证据,同时不给路由设备增加常驻成本 |
|
||||
| D-235 | Worker management 的 external ceremony、durable audit、同 issuer leaf revocation 与 client CA rollover 必须形成一个可独立重判的统一 release evidence,不能由人工核对四个 `passed` 布尔值。聚合器只接受 D-229 v1、D-230 v1、D-232 v2、D-234 v1 四份 canonical owner-private source,重跑原 validator、复算 durable→ceremony 及 PKI/CA→ceremony+durable 摘要链,并要求相同 external issuer/profile/operator、endpoint/server trust/inspect command、cluster/collector/Deployment UID。D-232/D-234 可在不同受审窗口执行,不伪造跨协议 generation 连续性;各自内部 rollout/Pod replacement 仍须成立。final 只含 source/identity/transport/deployment 摘要与低敏事实,以 `0600` no-replace+fsync 发布;独立 auditor 必须同时读取 final 和四份 source、重建 canonical report 后完全相等,拒绝 v1 PKI、source 替换、operator/transport/deployment 漂移、false/extra/sensitive 和时间倒置。不得新增 package、依赖、migration、服务、controller、timer、watcher、listener、Pool 或 Profile artifact | Accepted(ADR-0252:runner/source-aware auditor 7/7,覆盖完整聚合、摘要链断裂、operator/transport/Deployment 漂移、source false gate、final claimed drift/extra/false/sensitive、时间倒置与 exact CLI;顶层 evidence/audit 命令和生产归档 runbook 已完成。workspace 保持 19 个 QL3 package、零新依赖;真实 production 四 source + final 归档仍是发布门) | 单看最终 gate 不能证明 source 文件或跨报告作用域一致;把全部 source 嵌入 final 会复制事实和 schema;强求两个正交维护操作的 generation 连续会制造伪约束;另建 package/daemon 会增加路由器和发布面成本。source digest graph、共同 authority/transport/deployment binding 与必须携带 source 的离线重判形成最小可复验发布证明 |
|
||||
| D-236 | Worker management 的五份私密 release evidence 必须在镜像发布前完成 source-aware 重判,但不得上传到 GitHub artifact/cache,也不得与 registry/OIDC 写 authority 共处。唯一 image release workflow 只允许显式 dispatch 到与 version 完全一致的 protected `v3` tag;受 `ql3-production-release-evidence` environment 保护的 JIT self-hosted runner 从 commit-scoped `/run/qinglong3-release-evidence/$GITHUB_SHA` 固定名称挂载读取 final + 四 source,要求 canonical owner-private、D-235 audit 兼容、final 年龄不超过 24 小时且未来偏差不超过 5 分钟。顶层/evidence job 只有 contents read;publish 无条件 needs evidence,随后才在 GitHub-hosted runner 获得 GHCR/OIDC/attestation 写权限。禁止自动 tag push、用户路径、artifact/cache、source job output 与复用 runner;ephemeral 标签必须由外部 JIT provisioner 的一次注册/执行/销毁兑现。不增 package、依赖、migration、Profile artifact 或常驻资源 | Accepted(ADR-0253:release evidence gate 4 个新增场景与原 D-235 共 11/11;image release 静态/变异契约 26/26,覆盖 bypass、缺 dependency、persistent runner、artifact upload、非 commit mount、write authority 和 movable action。`audit:image-release:ql3` 返回 source-aware/private ephemeral/86400 秒/no artifact;真实 protected environment、JIT runner 与 evidence-backed GHCR 发布记录待取得) | 把 source 上传 artifact 扩大 custody/retention;只传 final 无法重判 source;publisher 同时读取证据与持有写 token 会合并安全域;自动 tag trigger 留下审批竞态;跨 workflow 查询成功状态产生 commit/tag 重放复杂度。同一 dispatch 内只读私密 pre-job 与强 needs 是最小失败关闭边界 |
|
||||
| D-237 | 三个 production image 必须在发布前对 amd64/arm64 的真实 OS package 执行 HIGH/CRITICAL 扫描,且扫描对象必须由不可覆盖的 base digest 决定。control/admin/local 的 build/runtime stage 统一固定 exact Node 24.18.0 Bookworm multiarch digest,删除 control/admin `ARG NODE_IMAGE`;CI 复用六个 native image,release 另建只读六矩阵 candidate job,publisher 同时 needs D-236 evidence 与全部 scan。Trivy 固定 0.70.0,action 固定 v0.36.0 full commit;OS-only、unfixed 不忽略、exit 1、cache false,scanner/DB 不可用失败。central exact JSON policy 当前空;例外只允许唯一排序 CVE、image subset、OS purl、owner、ticket、理由与未来最多 30 天 expiry,并生成每 image 的 `0600` no-replace YAML;禁止裸 ignore、path skip、allow-all Rego、永久 VEX 或 library 漏洞混入。不增 package、runtime dependency、migration 或 Profile 稳态资源 | Accepted(ADR-0254:policy 8/8、image release contract 34/34、Cluster deployment 31/31;静态审计返回 exact scanner/action、双架构、HIGH/CRITICAL、OS-only、ignoreUnfixed=false、30-day maximum,当前 exceptionCount=0。本机官方 scanner 下载无进展后中止并清理,未声称 live clean;GitHub-hosted 六矩阵和 evidence-backed GHCR 发布记录待取得) | 只扫 amd64 不能证明 arm64;发布后扫已经污染 registry;`ignore-unfixed` 是无 owner/expiry 的全局例外;直接维护 Trivy YAML 缺 image scope 与最长周期;mutable base/action tag 已有真实供应链风险。digest-pinned native preflight 与严格生成式例外把构建身份、漏洞判断和风险接受闭合在 publish 前 |
|
||||
| D-237 | 五个 production image 必须在发布前对 amd64/arm64 的真实 OS package 执行 HIGH/CRITICAL 扫描,且扫描对象必须由不可覆盖的 base digest 决定。四个 Dockerfile 的 build stage 固定 exact Node 24.18.0 Bookworm multiarch digest,runtime stage 固定 exact Node 24.18.0 Alpine 3.23 multiarch digest,删除 control/admin `ARG NODE_IMAGE`;CI/release 对 control/control-ai/admin/local/worker 执行十个 native scan,publisher 同时 needs D-236 evidence 与全部 scan。Trivy 固定 0.70.0,action 固定 v0.36.0 full commit;OS-only、unfixed 不忽略、exit 1、cache false,scanner/DB 不可用失败。central exact JSON policy 当前空;例外只允许唯一排序 CVE、image subset、OS purl、owner、ticket、理由与未来最多 30 天 expiry,并生成每 image 的 `0600` no-replace YAML;禁止裸 ignore、path skip、allow-all Rego、永久 VEX 或 library 漏洞混入。不增 package、runtime dependency、migration 或 Profile 稳态资源 | Accepted(ADR-0254:2026-08-22 同版 Bookworm/Trixie/Distroless 对比后,固定 Alpine multiarch digest 在 Trivy 0.70.0 同库扫描下 amd64/arm64 均为 0 HIGH/CRITICAL;静态/负向审计继续约束双基座 exact digest、双架构、OS-only、ignoreUnfixed=false 与 30-day maximum,当前 exceptionCount=0;完整十镜像远端扫描和 evidence-backed GHCR 发布记录仍是合并门) | 只扫 amd64 不能证明 arm64;发布后扫已经污染 registry;`ignore-unfixed` 是无 owner/expiry 的全局例外;直接维护 Trivy YAML 缺 image scope 与最长周期;把完整 Bookworm 工具链带入运行镜像既扩大路由器体积又放大攻击面。digest-pinned split build/runtime、native preflight 与严格生成式例外把构建身份、漏洞判断和风险接受闭合在 publish 前 |
|
||||
| D-238 | Release 漏洞门必须证明“被扫描的 OCI graph 就是被发布的 OCI graph”,相同 source 的二次 build 不得代替 artifact identity。六个 native job 各自只 build 一次带 SBOM/provenance 的 OCI layout tar,Trivy 对 exact tar 执行 D-237 gate;成功后解包、完整审计并生成绑定 platform/source/native root/manifest/config/attestation 的 evidence,以 run ID + attempt + image + architecture 唯一命名、1-day、no-overwrite artifact 传给 publisher。publisher 禁止 QEMU/Buildx/Dockerfile/rebuild,只能重验两份 native graph、确定性构造双架构 index 和 final OS vulnerability predicate;checksum-pinned regctl 只按 `IMAGE@DIGEST` import。远端 digest 的 Cosign、SLSA、CycloneDX、OS vulnerability、manifest 与 rollout 全部通过后,version/完整 commit tag 才作为最后一步创建。私密 D-236 evidence 不进入 artifact;不增 package、runtime dependency、migration 或 Profile 稳态资源 | Accepted(ADR-0255:OCI/release 定向 57/57;workflow YAML 与 repository audit 全绿,输出 `buildOnce=true`、`attestedToPublishedDigest=true`、`rebuildAfterScan=false`、`tagAfterVerification=true`。PostgreSQL 18.4 arm64 HA 同轮重跑 `gates.passed=true` 且 Docker HA 容器/卷/网络零残留;本机 OCI attested build 因 BuildKit SBOM scanner 网络超时未取得 live clean,GitHub-hosted 六矩阵、regctl→GHCR exact-digest import 与最终 tag 记录待取得) | 扫描一次后按相同 source 再 build 仍允许构建环境或依赖漂移;candidate tag 在 gate 前污染 registry且可移动;publisher 保留 build authority 会重新打开替换面;提前打 tag 会把未完成证明的 digest 暴露给部署者。build-once、同 run immutable graph、repository merger、digest-only import 和 tag-last 将漏洞判断与最终发布身份闭合 |
|
||||
|
||||
| D-239 | Fresh Edge/Standalone 必须提供受支持的 TaskDefinition create/update/enable/disable/inspect/list 产品入口,不能要求部署者直接写 SQLite 或调用 Repository。既有 `ql3-task` binary 只从 deployment root 内当前 UID `0600` 非 symlink command file 接受 `task.put|task.inspect|task.list`;put 以 `expectedRevision=null|current` 区分 create/update,enable/disable 都追加 immutable revision,不原地修改或删除。每次命令只建立短生命周期进程和单 SQLite authority,要求 strong User 与 `task.create|task.update|task.read` Policy;写事务内重新验证 credential/Identity/pepper、Project/RoleBinding fence,原子提交 allowed audit、Task head/revision、mutation replay 和适用的 local execution revision。exact replay 绑定 mutation event、request、actor、fence 与 immutable occurredAt,semantic/audit/revision 漂移失败关闭;CLI 只返回有界 current-head 元数据,不回显 spec/config/command/SecretRef/credential/path。实现只增加现有四包 subpath,workspace 保持 19,不增依赖、migration、daemon、timer、watcher、listener、Pool 或端口。Cluster 不复用本机 credential/SQLite CLI,必须后续提供 PostgreSQL/RBAC/多副本管理 transport | Accepted(ADR-0256:真实 SQLite/Owner CLI 5/5 覆盖 create/exact replay/disable/inspect/list、operator allow/viewer deny、credential/Policy race 原子回滚、Task/audit semantic drift、private command file 与低敏输出;Owner CLI closure strict TypeScript 通过。PostgreSQL 18.4 arm64 HA 同轮 `gates.passed=true`,完成 remote_apply、timeline 1→2、old-primary fence/rewind/read-only rejoin、双 fresh control,Docker 容器/网络/卷零残留;该证据只声明 Cluster 基线未回归) | 新建单用途 package 会反转 D-207 的 19 包收敛;把写 authority 暴露给常驻 application 会增加低配设备空闲成本;直接 SQL 绕过认证、Policy、audit、semantic registry 与 replay;原地 enabled bool 会破坏历史;把 SQLite command file 当集群协议会丢失 PostgreSQL HA/RBAC fence。既有短生命周期 CLI、事务内复验与 append-only revision 是当前最小可用且可审计闭环 |
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
> ADR-0196 已把该供应链扩展为 `control|admin|local` 三个 profile,并将唯一
|
||||
> 发布入口迁移到 `.github/workflows/ql3-image-release.yml`。本 ADR 以下
|
||||
> control/admin 数字保留为建立该机制时的历史证据。ADR-0254 随后删除 control/admin 可覆盖的
|
||||
> `NODE_IMAGE` build arg,将两个 build/runtime stage 与 local 一起固定到同一 Node 多架构 digest,并增加六矩阵
|
||||
> OS vulnerability pre-publish gate。
|
||||
> `NODE_IMAGE` build arg,并增加跨架构 OS vulnerability pre-publish gate。2026-08-22 的 ADR-0254 修订进一步把
|
||||
> build stage 保留在固定 Bookworm digest、runtime stage 切到零 HIGH/CRITICAL 的固定 Alpine 3.23 digest,覆盖
|
||||
> `control|control-ai|admin|local|worker` 十个 native image。
|
||||
|
||||
## 背景
|
||||
|
||||
|
||||
+11
-10
@@ -19,18 +19,19 @@ commit SHA。D-237 不能用 movable `@v0.x` 或 `latest` 引入一个拥有 wor
|
||||
|
||||
## 决策
|
||||
|
||||
1. control、admin、local 的 build/runtime stage 统一固定
|
||||
`node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d`。
|
||||
control/admin 删除 `ARG NODE_IMAGE`,不得允许 build arg 覆盖 base;三个镜像继续拥有独立 Dockerfile、应用闭包和
|
||||
最终 image digest。
|
||||
1. control、control-ai、admin、local、worker 的 dependency/build stage 固定
|
||||
`node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d`,最终 runtime stage 固定更小的
|
||||
`node:24.18.0-alpine3.23@sha256:595398b0081eacda8e1c4c5b97b76cd1020e4d58a8ebcb4843b9bca1e79e7436`。
|
||||
control/admin 删除 `ARG NODE_IMAGE`,所有 runtime base 都不得由 build arg 覆盖;四个 Dockerfile 继续拥有独立应用闭包和
|
||||
最终 image digest。构建与运行基座分离,避免把编译工具链和 Bookworm 的 Perl/util-linux/ncurses 包带入低配设备与集群运行镜像。
|
||||
2. scanner 固定为 Trivy `v0.70.0`,GitHub Action 固定完整 commit
|
||||
`ed142fd0673e97e23eac54620cfb913e5ce36c25`(action `v0.36.0`)。禁止 tag、`master`、`latest`、
|
||||
`continue-on-error` 和 scanner cache;网络、release asset 或 vulnerability DB 不可用均失败关闭。
|
||||
3. 只扫描 `vuln-type=os`、`scanners=vuln`、severity `HIGH,CRITICAL`,`ignore-unfixed=false`、exit code 1。
|
||||
npm/library advisory 继续由既有 production dependency audit 独立负责,不能用 OS 例外隐藏应用依赖漏洞。
|
||||
4. `.github/workflows/ql3-ci.yml` 复用已经存在的 native build:control/admin 各 amd64+arm64,local
|
||||
amd64+arm64,共六个真实本地 image。每个 build 后生成 image-scoped ignore view 并执行 Trivy。
|
||||
5. release workflow 增加独立只读 `os-vulnerability` 六矩阵 job,在发布前用 exact Dockerfile、base digest、lock 和
|
||||
4. `.github/workflows/ql3-ci.yml` 复用已经存在的 native build:control、control-ai、admin、local、worker
|
||||
各 amd64+arm64,共十个真实本地 image。每个 build 后生成 image-scoped ignore view 并执行 Trivy。
|
||||
5. release workflow 增加独立只读 `os-vulnerability` 十矩阵 job,在发布前用 exact Dockerfile、base digest、lock 和
|
||||
source revision 构建 native candidate。`publish` 必须同时依赖 D-236 private evidence 与全部 OS scan 成功,
|
||||
才能获得 GHCR/OIDC/attestation 写权限。scan job 不读取 D-236 私密 source,不参与签名或 publish。
|
||||
6. 唯一例外事实源为 `deploy/containers/ql3-os-vulnerability-exceptions.json`。顶层和每条 entry 都是 exact shape;
|
||||
@@ -83,9 +84,9 @@ commit SHA。D-237 不能用 movable `@v0.x` 或 `latest` 引入一个拥有 wor
|
||||
- image release contract 34/34:新增覆盖 CI/release action pin、六矩阵、publish dependency、unfixed、OS-only、
|
||||
cache 与既有签名/SBOM/provenance 门;
|
||||
- Cluster deployment 31/31,包含 control/admin mutable/overridable base 负向测试;
|
||||
- 本机 arm64 exact Dockerfile build 已通过:control `sha256:58ca2905c6489d3051663804f07adb0ea24dce734cc96863f882c8e5cb73579c`、
|
||||
admin `sha256:79f8eda7194cf63669ba144917eabecd11faa0546858ac1feb7ee52ccffc5f27`,均为 arm64、
|
||||
`10001:10001`;验证 image 已删除;
|
||||
- 2026-08-22 CI 的 Bookworm runtime 扫描在 amd64/arm64 同时发现 30 个 HIGH/CRITICAL;同版 Trixie Slim 为 51 个,
|
||||
Debian 13 distroless 为 1 个无修复 HIGH。固定的 Alpine 3.23 multiarch digest 使用同一 Trivy 0.70.0 与同一数据库扫描,
|
||||
amd64/arm64 均为 0 HIGH/CRITICAL,且 Node 版本仍为 24.18.0;完整十镜像远端扫描仍是合并门;
|
||||
- `audit:image-release:ql3` 返回 Trivy 0.70.0、exact action commit、amd64/arm64、OS-only、HIGH/CRITICAL、
|
||||
`ignoreUnfixed=false`、maximum exception 30 days;
|
||||
- 当前 policy `exceptionCount=0`;workspace 保持 19 个 package,无新增 runtime dependency。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# QingLong 3.0 镜像 OS 漏洞门
|
||||
|
||||
本流程覆盖 `control|admin|local × amd64|arm64` 六个 release candidate 的 Debian/base image package,不替代 npm
|
||||
本流程覆盖 `control|control-ai|admin|local|worker × amd64|arm64` 十个 release candidate 的 OS/base image package,不替代 npm
|
||||
production dependency audit、CycloneDX、BuildKit SBOM/provenance、Cosign 或 GitHub attestation。
|
||||
|
||||
## 日常检查
|
||||
@@ -17,7 +17,7 @@ pnpm audit:cluster-deployment:ql3
|
||||
{"schemaVersion":1,"fixture":"qinglong/image-os-vulnerability-exceptions@v1","compatible":true,"exceptionCount":0,"imageExceptionCounts":{"admin":0,"control":0,"local":0}}
|
||||
```
|
||||
|
||||
真实 scan 在 QL3 CI 已有六个 native build 后执行;受保护 release 的六个 native job 各自只构建一次 OCI layout tar,
|
||||
真实 scan 在 QL3 CI 已有十个 native build 后执行;受保护 release 的十个 native job 各自只构建一次 OCI layout tar,
|
||||
Trivy 直接扫描该 tar。扫描成功后才解包、审计并上传同一 OCI graph;publisher 只合并 amd64/arm64 graph,不再 build。
|
||||
只有六份 artifact 和 D-236 私密 evidence job 全部成功,publisher 才会启动。scanner/DB 网络故障与漏洞命中使用相同
|
||||
的失败关闭结果,但日志会区分下载错误和 finding。
|
||||
@@ -80,8 +80,8 @@ pnpm audit:image-release:ql3
|
||||
1. 阅读 Trivy 官方 release 与 security advisory,确认目标版本不在已知暴露窗口;
|
||||
2. 解析 signed/immutable action release 到完整 commit SHA,审查 composite action 的所有 nested action pin;
|
||||
3. 固定 scanner exact version,禁止 `latest`;保持 cache false、OS-only、unfixed 不忽略;
|
||||
4. 对 Node base 的多架构 manifest digest 执行签名/来源核验;三个 production Dockerfile 必须同步更新 exact digest;
|
||||
5. 更新 ADR、静态审计 expectation 与 mutation tests;执行六个 native scan 后才能发布;
|
||||
4. 对 Node base 的多架构 manifest digest 执行签名/来源核验;四个 production Dockerfile 的 runtime stage 必须同步更新 exact digest;
|
||||
5. 更新 ADR、静态审计 expectation 与 mutation tests;执行十个 native scan 后才能发布;
|
||||
6. 修复后删除已不需要的 exceptions,不等待 `expiresOn`。
|
||||
|
||||
## 失败恢复
|
||||
|
||||
Reference in New Issue
Block a user