Compare commits

...
Author SHA1 Message Date
aios 81fe0d0321 fix(actions): make V1R2C3 tag execution idempotent 2026-07-08 01:17:37 +08:00
3 changed files with 20 additions and 5 deletions
@@ -247,12 +247,12 @@ class H(BaseHTTPRequestHandler):
if not a: return
ver=data.get('version') or data.get('tag')
if not re.match(r'^V\d+R\d+C\d+(-[A-Za-z0-9_.-]+)?$', ver or ''): return self.sendj({'error':'version must match VxRxCx'},400)
if data.get('confirm') != True:
self.sendj({'status':'confirm_required','operation':'tag','hint':'This operation creates a Git tag. Confirm to proceed.','x-openai-isConsequential':True}, 428)
return
if a['role'] != 'owner' or not data.get('execute'):
if a['role'] != 'owner' or data.get('execute') != True:
b=checkout(data.get('branch') or f'request/tag-{safe(ver)}', 'main', True); req={'version':ver,'requested_by':a['account'],'approval_required':True,'created_at':now()}; r=write_json(f'baseline/tag_requests/{safe(ver)}.json', req); c=commit([r], f'chore(chatgpt): request tag {ver}'); return self.sendj({'status':'approval_required','branch':b,'commit':c})
out=sh(['tag','-a',ver,'-m',data.get('message') or f'release {ver}'], True); self.sendj({'status':'tagged','version':ver,'git':out,'sync':sync_tag(ver)})
existing=sh(['rev-parse','-q','--verify',f'refs/tags/{ver}'])
if existing['code'] == 0 and existing['stdout']:
return self.sendj({'status':'already_tagged','version':ver,'rev':existing['stdout'],'sync':sync_tag(ver),'x-openai-isConsequential':True})
out=sh(['tag','-a',ver,'-m',data.get('message') or f'release {ver}'], True); self.sendj({'status':'tagged','version':ver,'git':out,'sync':sync_tag(ver),'x-openai-isConsequential':True})
def rollback(self,data):
a=self.need('rollback:request');
if not a: return
+1
View File
@@ -198,6 +198,7 @@ paths:
post:
operationId: requestOrCreateTag
summary: Request tag creation; owner execution is required for direct tag
x-openai-isConsequential: true
security: [{bearerAuth: []}]
requestBody:
required: true
@@ -0,0 +1,14 @@
# V1R2C3 Tag Execute Idempotent Permission Report
Status: implemented
Changes:
- requestOrCreateTag no longer requires an undocumented backend `confirm` field.
- Owner execution still requires `execute=true` and owner role.
- Existing tag returns `already_tagged` and syncs the tag ref instead of failing.
- OpenAPI marks requestOrCreateTag as consequential.
Security:
- No credential values are committed.
- Runtime permission source changes are stored only in `/data/aios-gitops/runtime/secrets/gitops.tokens`.
- Force push is not used.