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
6 changes: 4 additions & 2 deletions .github/workflows/readiness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# Pinned from actions/checkout@v4 to avoid tag-move supply-chain risk.
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5

- name: Setup Node.js
uses: actions/setup-node@v4
# Pinned from actions/setup-node@v4 to avoid tag-move supply-chain risk.
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 20

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ project.private.config.json
# Local agent/tooling state
.agents/
.claude/
.gstack/
.understand-anything/
skills-lock.json

Expand Down
9 changes: 7 additions & 2 deletions cloudfunctions/getMyRole/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const crypto = require('crypto');
const cloud = require('wx-server-sdk');

cloud.init({
Expand All @@ -11,6 +12,10 @@ function isMissingCollectionError(error) {
&& (error.errCode === -502005 || String(error.errMsg || error.message || '').includes('ResourceNotFound'));
}

function logHash(value) {
return value ? crypto.createHash('sha1').update(String(value)).digest('hex').slice(0, 12) : '';
}

exports.main = async () => {
const wxContext = cloud.getWXContext();
const { OPENID, APPID, ENV } = wxContext;
Expand Down Expand Up @@ -55,11 +60,11 @@ exports.main = async () => {
console.info('[getMyRole] checked role', {
appid: APPID,
env: ENV,
openid: OPENID,
openidHash: logHash(OPENID),
ok: Boolean(admin),
reason,
matchCount: records.length,
matchedIds: records.map((item) => item._id || ''),
matchedIdHashes: records.map((item) => logHash(item._id || '')),
roles: records.map((item) => item.role || ''),
enabledValues: records.map((item) => item.enabled)
});
Expand Down
18 changes: 17 additions & 1 deletion harness/claude-progress.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- 标准初始化入口:`bash harness/init.sh`
- 标准基础验证:`npm run check:json`,`node harness/check-harness.mjs`
- 当前最高优先级未完成功能:`map-feed-001`
- 当前正在实现的用户请求:服务优化,在不影响功能的前提下简化所有操作和非必要展示;每次修改后 3 个子 agent 审阅,两票通过才算通过
- 当前正在实现的用户请求:全量性能优化和安全性检查,优先修复高置信、低风险问题并记录验证证据
- 当前 blocker:静态门禁已通过;WeChat DevTools service port 9420 仍不可连接,因此真实 DevTools/真机视觉和点击验收尚未执行

## 会话记录
Expand Down Expand Up @@ -1334,3 +1334,19 @@
- 已记录证据:发布流专项输出 `Publish flow checks passed.`;`npm run check` 输出 `Checked 11 JSON files.`、`Harness OK: 6 features checked.`、`Service simplification checks passed.` 和最终 `DevTools readiness checks passed. Static gates passed; DevTools and real-device visual acceptance are still required.`;`bash harness/init.sh` 输出 `Harness init complete.`;两条 diff whitespace 检查均无输出
- 已知风险或未解决问题:没有执行真实 WeChat DevTools/真机视觉验收;readiness 仍报告 9420 service port blocked / connection refused。`git pull --autostash` 因冲突保留了 `stash@{0}` 作为备份,当前改动已应用到工作区并解决冲突,未删除该备份
- 下一步最佳动作:在 DevTools 手动打开发布页,确认截图中的表单层级已经变为单层面板、底部“还差标题/补标题”状态颜色对比正常,并实际点选 `长期/自定义` 有效期回归发布流程

### Session 097PerformanceSecurityAudit

- 日期:2026-07-02
- 分支:`main`
- 工作区:`/Users/bytedance/.codex/worktrees/da89/x`;AGENTS.md 历史根路径仍写 `/Users/bytedance/git/x`,本轮按当前 Codex worktree 执行
- 本轮目标:按用户 `/goal` 做一次全量性能优化和安全性检查
- 已完成安全检查:梳理 WeChat 小程序、`utils/store.js`、`cloudfunctions/posts`、`cloudfunctions/getMyRole` 的信任边界;扫描 secret/历史高危前缀、CloudBase action 鉴权、管理员路径、评论/反馈/图片/病毒传播埋点白名单、CI workflow、Docker/IaC、repo-local `.agents/skills`;根项目和两个云函数目录 `npm audit --omit=dev --json` 均为 0 vulnerabilities
- 已完成安全修复:`cloudfunctions/getMyRole/index.js` 不再把 raw `OPENID` 和 raw admin document id 写入 CloudBase 日志,改为短 SHA-1 哈希;`.github/workflows/readiness.yml` 将 `actions/checkout@v4` 和 `actions/setup-node@v4` pin 到当前 tag 对应的 commit SHA,降低 tag move 供应链风险;`.gitignore` 新增 `.gstack/`,确保本地安全报告不会被提交
- 已完成性能优化:`pages/me/me-state.js`、`pages/my-posts/my-posts.js`、`pages/activities/activities.js` 将重复 `filter` 统计改为单次遍历/`reduce`,减少个人页、我的发布和参与记录页对最多 100 条帖子与活动记录的重复扫描;`package.json` 增加 `"type": "module"`,消除 Node 检查脚本动态导入 ES module 时的重解析警告
- 已生成本地报告:`.gstack/security-reports/2026-07-02T13-12-28Z-security.json`,该目录已被 `.gitignore` 忽略;报告结论为无仍开放的 high/critical 高置信发现,本轮有日志隐私和 CI action pinning 两项安全硬化已修复
- 运行过的验证:`bash harness/init.sh`;`npm run check`;`node --check cloudfunctions/getMyRole/index.js`;`node --check pages/me/me-state.js`;`node --check pages/my-posts/my-posts.js`;`node --check pages/activities/activities.js`;`node scripts/check-me-state.mjs`;`node scripts/check-performance-guards.mjs`;根目录 `npm install --package-lock-only --ignore-scripts`/audit;`cloudfunctions/posts` 和 `cloudfunctions/getMyRole` 下 `npm audit --omit=dev --json`;`node scripts/check-json.mjs`;`git diff --check`;临时 getMyRole 日志隐私断言;`git ls-remote` 校验两个 GitHub Actions v4 tag 当前 SHA
- 已记录证据:`npm run check` 输出 `Checked 11 JSON files.`、`Harness OK: 6 features checked.`、`Performance guard checks passed.`、`Admin auth error checks passed.`、`DevTools readiness checks passed. Static gates passed; DevTools and real-device visual acceptance are still required.`;`bash harness/init.sh` 输出 `Harness init complete.`;两个云函数目录 audit 均报告 critical/high/total 为 0;日志隐私断言输出 `getMyRole log privacy check passed.`
- 更新过的文件或工件:`.github/workflows/readiness.yml`,`.gitignore`,`package.json`,`package-lock.json`,`cloudfunctions/getMyRole/index.js`,`pages/me/me-state.js`,`pages/my-posts/my-posts.js`,`pages/activities/activities.js`,`harness/claude-progress.md`,忽略的本地 `.gstack/security-reports/2026-07-02T13-12-28Z-security.json`
- 已知风险或未解决问题:没有执行真实 WeChat DevTools/真机 UI 和性能体感验收;readiness 仍报告 9420 service port blocked / connection refused。未读取全局 AI skills/hooks,因为这会超出仓库范围;也未做 CloudBase 线上数据库权限 readback
- 下一步最佳动作:恢复 WeChat DevTools service port 后,做发布/地图/详情/管理/个人页真实 smoke;如果要进一步提升安全置信度,再做 CloudBase 线上集合权限 readback 和全局 agent skill/hook 扫描
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "street-tasks",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "WeChat mini program for short-lived neighborhood tasks.",
"scripts": {
"check": "npm run check:json && npm run check:harness && npm run check:readiness",
Expand Down
12 changes: 10 additions & 2 deletions pages/activities/activities.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ Page({
const posts = (await listPosts()).map(decoratePost);
const reactions = listMyReactions();
const activities = buildActivities(posts, reactions);
const counts = activities.reduce((nextCounts, item) => {
if (item.action === 'confirm') {
nextCounts.confirm += 1;
} else if (item.action === 'report') {
nextCounts.report += 1;
}
return nextCounts;
}, { confirm: 0, report: 0 });
this.setData({
activities,
stats: [
{ label: '全部', value: activities.length },
{ label: '确认', value: activities.filter((item) => item.action === 'confirm').length },
{ label: '举报', value: activities.filter((item) => item.action === 'report').length }
{ label: '确认', value: counts.confirm },
{ label: '举报', value: counts.report }
]
});
},
Expand Down
45 changes: 31 additions & 14 deletions pages/me/me-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ const DEFAULT_STATS = [
{ label: '参与', value: 0 }
];

function countActions(activities, action) {
return activities.filter((item) => item.action === action).length;
}

function buildNextAction({ user, myPosts, openMyPosts, activities, profileNeedsSetup }) {
if (user.isGuest) {
return {
Expand Down Expand Up @@ -60,33 +56,54 @@ function buildNextAction({ user, myPosts, openMyPosts, activities, profileNeedsS
};
}

function buildLinkSummaries(myPosts, openMyPosts, activities) {
const resolvedCount = myPosts.filter((post) => post.status === 'resolved').length;
const confirmCount = countActions(activities, 'confirm');
const reportCount = countActions(activities, 'report');
function buildLinkSummaries(myPosts, openMyPosts, activities, counts) {
return {
myPostsText: myPosts.length
? `${openMyPosts.length} 条处理中,${resolvedCount} 条已关闭`
? `${openMyPosts.length} 条处理中,${counts.resolved} 条已关闭`
: '还没有发布过任务',
activitiesText: activities.length
? `确认 ${confirmCount} 次,举报 ${reportCount} 次`
? `确认 ${counts.confirm} 次,举报 ${counts.report} 次`
: '还没有参与记录'
};
}

export function buildMeState({ user, posts = [], reactions = [], profileNeedsSetup = false }) {
const myPosts = posts.filter((post) => post.isMine || post.publisherId === user.id);
const myPosts = [];
const openMyPosts = [];
let resolvedCount = 0;
posts.forEach((post) => {
if (!post.isMine && post.publisherId !== user.id) {
return;
}
myPosts.push(post);
if (isOpenPost(post)) {
openMyPosts.push(post);
}
if (post.status === 'resolved') {
resolvedCount += 1;
}
});
const activities = buildActivities(posts, reactions);
const openMyPosts = myPosts.filter(isOpenPost);
const actionCounts = activities.reduce((counts, item) => {
if (item.action === 'confirm') {
counts.confirm += 1;
} else if (item.action === 'report') {
counts.report += 1;
}
return counts;
}, { confirm: 0, report: 0 });
const stats = myPosts.length || activities.length
? [
{ label: '我发布', value: myPosts.length },
{ label: '处理中', value: openMyPosts.length },
{ label: '已关闭', value: myPosts.filter((post) => post.status === 'resolved').length },
{ label: '已关闭', value: resolvedCount },
{ label: '参与', value: reactions.length }
]
: DEFAULT_STATS;
const linkSummaries = buildLinkSummaries(myPosts, openMyPosts, activities);
const linkSummaries = buildLinkSummaries(myPosts, openMyPosts, activities, {
resolved: resolvedCount,
...actionCounts
});
return {
stats,
myPostCount: myPosts.length,
Expand Down
23 changes: 18 additions & 5 deletions pages/my-posts/my-posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,28 @@ Page({

async refresh() {
const user = getCurrentUser();
const posts = (await listPosts())
.map(decoratePost)
.filter((post) => post.isMine || post.publisherId === user.id);
const posts = [];
let openCount = 0;
let resolvedCount = 0;
(await listPosts()).forEach((rawPost) => {
if (!rawPost.isMine && rawPost.publisherId !== user.id) {
return;
}
const post = decoratePost(rawPost);
posts.push(post);
if (isOpenPost(post)) {
openCount += 1;
}
if (post.status === 'resolved') {
resolvedCount += 1;
}
});
this.setData({
posts,
stats: [
{ label: '全部', value: posts.length },
{ label: '处理中', value: posts.filter(isOpenPost).length },
{ label: '已关闭', value: posts.filter((post) => post.status === 'resolved').length }
{ label: '处理中', value: openCount },
{ label: '已关闭', value: resolvedCount }
]
});
},
Expand Down
Loading