Discussion: profiles.json v2 model for multi-service environments #100

Open
opened 2026-07-02 17:06:59 -05:00 by sysadmin · 5 comments
Owner

Discussion: profiles.json v2 model for multi-service environments

Background

The current ~/.config/gitea-tools/profiles.json model is too flat and Gitea-specific.

Current shape is roughly:

  • profiles.mdcps
  • profiles.prgs-author
  • profiles.prgs-reviewer

This worked for Gitea-only workflows, but we now need to support multiple environments and multiple services.

Real environments

PRGS / local server environment

  • Currently only has Gitea.
  • May later add Jenkins, GlitchTip, or other services.
  • Gitea requires two identities:
    • author identity
    • reviewer/merge identity
  • This split is required so LLMs cannot self-review or self-merge.

MDCPS environment

  • Has Gitea, Jenkins, and GlitchTip.
  • Currently only one Gitea user is configured.
  • Needs a second Gitea user so review/merge workflows can work safely.
  • Jenkins and GlitchTip need service credentials too.
  • These services may not need the same author/reviewer split as Gitea.

Problem

The current JSON mixes several concepts into one flat profile object:

  • environment name
  • service name
  • identity role
  • execution profile
  • auth keychain reference
  • allowed operations
  • default owner/repo

Before we add Jenkins and GlitchTip credentials, we should agree on the next config model.

Proposed direction

Move to a versioned profiles.json v2 model with a three-level hierarchy:

environment → service → identity

Canonical profile address:

{environment}.{service}.{identity}

Examples:

prgs.gitea.author
prgs.gitea.reviewer
mdcps.gitea.author
mdcps.gitea.reviewer
mdcps.jenkins.reader
mdcps.glitchtip.reader

Old flat names would continue through aliases:

{
  "aliases": {
    "mdcps": "mdcps.gitea.author",
    "prgs-author": "prgs.gitea.author",
    "prgs-reviewer": "prgs.gitea.reviewer"
  }
}

Security requirements

  • Secrets must not be stored in JSON.
  • JSON should store only keychain references.
  • Auth entries should remain shaped like:
{
  "type": "keychain",
  "id": "some-keychain-id"
}
  • Runtime whoami identity must remain the source of truth.
  • Config-declared roles must not bypass self-review/self-merge checks.
  • forbidden_operations must always override allowed_operations.
  • Missing or empty allowed_operations should continue to fail closed unless explicitly changed.

Proposed keychain naming convention

prgs.gitea.author.token
prgs.gitea.reviewer.token
mdcps.gitea.author.token
mdcps.gitea.reviewer.token
mdcps.jenkins.reader.token
mdcps.glitchtip.reader.token

Existing keychain IDs can continue to work through explicit auth.id references. Renaming existing keychain items should be optional/lazy.

Example v2 shape

{
  "version": 2,
  "environments": {
    "prgs": {
      "description": "PRGS local server environment",
      "services": {
        "gitea": {
          "base_url": "https://gitea.prgs.cc",
          "default_owner": "Scaled-Tech-Consulting",
          "identities": {
            "author": {
              "role": "author",
              "username": "jcwalker3",
              "auth": {
                "type": "keychain",
                "id": "prgs.gitea.author.token"
              },
              "execution_profile": "prgs-author",
              "audit_label": "prgs-author",
              "allowed_operations": [
                "gitea.read",
                "gitea.issue.create",
                "gitea.issue.comment",
                "gitea.branch.push",
                "gitea.pr.create",
                "gitea.pr.comment"
              ],
              "forbidden_operations": [
                "gitea.pr.approve",
                "gitea.pr.merge"
              ]
            },
            "reviewer": {
              "role": "reviewer",
              "username": "sysadmin",
              "auth": {
                "type": "keychain",
                "id": "prgs.gitea.reviewer.token"
              },
              "execution_profile": "prgs-reviewer",
              "audit_label": "prgs-reviewer",
              "default_repo": "Gitea-Tools",
              "allowed_operations": [
                "gitea.read",
                "gitea.pr.review",
                "gitea.pr.comment",
                "gitea.pr.approve",
                "gitea.pr.request_changes",
                "gitea.pr.merge",
                "gitea.branch.delete"
              ],
              "forbidden_operations": [
                "gitea.branch.push",
                "gitea.pr.create"
              ]
            }
          }
        }
      }
    },
    "mdcps": {
      "description": "MDCPS environment with Gitea, Jenkins, and GlitchTip",
      "services": {
        "gitea": {
          "base_url": "https://gitea.dadeschools.net",
          "identities": {
            "author": {
              "role": "author",
              "username": "913443",
              "auth": {
                "type": "keychain",
                "id": "mdcps.gitea.author.token"
              },
              "execution_profile": "mdcps-author",
              "audit_label": "mdcps-author",
              "allowed_operations": [
                "gitea.read",
                "gitea.issue.create",
                "gitea.issue.comment",
                "gitea.branch.push",
                "gitea.pr.create"
              ],
              "forbidden_operations": [
                "gitea.pr.approve",
                "gitea.pr.merge"
              ]
            },
            "reviewer": {
              "role": "reviewer",
              "username": "TBD-second-mdcps-user",
              "auth": {
                "type": "keychain",
                "id": "mdcps.gitea.reviewer.token"
              },
              "execution_profile": "mdcps-reviewer",
              "audit_label": "mdcps-reviewer",
              "allowed_operations": [
                "gitea.read",
                "gitea.pr.review",
                "gitea.pr.approve",
                "gitea.pr.request_changes",
                "gitea.pr.merge"
              ],
              "forbidden_operations": [
                "gitea.branch.push",
                "gitea.pr.create"
              ]
            }
          }
        },
        "jenkins": {
          "base_url": "https://jenkins.dadeschools.net",
          "identities": {
            "reader": {
              "role": "reader",
              "username": "svc-jenkins-read",
              "auth": {
                "type": "keychain",
                "id": "mdcps.jenkins.reader.token"
              },
              "execution_profile": "mdcps-jenkins-reader",
              "audit_label": "mdcps-jenkins-reader",
              "allowed_operations": [
                "jenkins.read",
                "jenkins.build.read"
              ],
              "forbidden_operations": [
                "jenkins.build.trigger",
                "jenkins.deploy",
                "jenkins.job.configure"
              ]
            }
          }
        },
        "glitchtip": {
          "base_url": "https://glitchtip.dadeschools.net",
          "identities": {
            "reader": {
              "role": "reader",
              "username": "svc-glitchtip-read",
              "auth": {
                "type": "keychain",
                "id": "mdcps.glitchtip.reader.token"
              },
              "execution_profile": "mdcps-glitchtip-reader",
              "audit_label": "mdcps-glitchtip-reader",
              "allowed_operations": [
                "glitchtip.read",
                "glitchtip.event.read"
              ],
              "forbidden_operations": [
                "glitchtip.event.read_raw",
                "glitchtip.issue.mutate",
                "glitchtip.admin"
              ]
            }
          }
        }
      }
    }
  },
  "aliases": {
    "mdcps": "mdcps.gitea.author",
    "prgs-author": "prgs.gitea.author",
    "prgs-reviewer": "prgs.gitea.reviewer"
  }
}

Proposed migration strategy

  1. Keep version: 1 files supported.
  2. Add support for version: 2.
  3. Resolve profile selection in this order:
    • alias
    • dotted path
    • fail closed
  4. Keep existing profile names working:
    • mdcps
    • prgs-author
    • prgs-reviewer
  5. Add a future migration helper that:
    • reads v1
    • writes v2
    • creates a backup
    • does not touch keychain secrets
    • defaults to dry-run
  6. Do not rename existing keychain entries unless explicitly requested.

Areas likely affected if approved

  • profile loading
  • auth resolution
  • operation gating
  • whoami tools
  • review/merge eligibility checks
  • CLI profile selection
  • config menu
  • tests
  • documentation

Open questions for review

  1. Should mdcps alias map to mdcps.gitea.author, or should it stay deny-all until the second user is ready?
  2. What is the second MDCPS Gitea username for reviewer/merge workflows?
  3. Should we keep one shared config file, or split per-service config files?
  4. Should future service MCPs use only dotted profile paths, or should we introduce generic selectors like MCP_ENV, MCP_SERVICE, and MCP_IDENTITY?
  5. Should old keychain IDs be renamed now, or should we keep them forever through explicit auth.id?
  6. Should whoami expose safe metadata like environment, service, and identity?
  7. Should operations be fully namespaced, such as gitea.pr.merge, or should backward-compatible unqualified operations like merge continue internally?
  8. Should Jenkins and GlitchTip initially be read-only only?

Proposed acceptance for this discussion

This issue can close only after reviewers agree on:

  • final v2 config shape
  • compatibility strategy
  • keychain naming approach
  • MDCPS reviewer identity requirement
  • whether implementation belongs in this repo or in a shared MCP control-plane config library

No implementation should begin until this discussion reaches a decision.


Reviewers and other LLM sessions: please comment directly on this issue with your recommendation per open question. Discussion only — no implementation, branches, or PRs until this reaches a decision.

# Discussion: profiles.json v2 model for multi-service environments ## Background The current `~/.config/gitea-tools/profiles.json` model is too flat and Gitea-specific. Current shape is roughly: - `profiles.mdcps` - `profiles.prgs-author` - `profiles.prgs-reviewer` This worked for Gitea-only workflows, but we now need to support multiple environments and multiple services. ## Real environments ### PRGS / local server environment - Currently only has Gitea. - May later add Jenkins, GlitchTip, or other services. - Gitea requires two identities: - author identity - reviewer/merge identity - This split is required so LLMs cannot self-review or self-merge. ### MDCPS environment - Has Gitea, Jenkins, and GlitchTip. - Currently only one Gitea user is configured. - Needs a second Gitea user so review/merge workflows can work safely. - Jenkins and GlitchTip need service credentials too. - These services may not need the same author/reviewer split as Gitea. ## Problem The current JSON mixes several concepts into one flat profile object: - environment name - service name - identity role - execution profile - auth keychain reference - allowed operations - default owner/repo Before we add Jenkins and GlitchTip credentials, we should agree on the next config model. ## Proposed direction Move to a versioned `profiles.json` v2 model with a three-level hierarchy: ```text environment → service → identity ``` Canonical profile address: ```text {environment}.{service}.{identity} ``` Examples: ```text prgs.gitea.author prgs.gitea.reviewer mdcps.gitea.author mdcps.gitea.reviewer mdcps.jenkins.reader mdcps.glitchtip.reader ``` Old flat names would continue through aliases: ```json { "aliases": { "mdcps": "mdcps.gitea.author", "prgs-author": "prgs.gitea.author", "prgs-reviewer": "prgs.gitea.reviewer" } } ``` ## Security requirements * Secrets must not be stored in JSON. * JSON should store only keychain references. * Auth entries should remain shaped like: ```json { "type": "keychain", "id": "some-keychain-id" } ``` * Runtime `whoami` identity must remain the source of truth. * Config-declared roles must not bypass self-review/self-merge checks. * `forbidden_operations` must always override `allowed_operations`. * Missing or empty `allowed_operations` should continue to fail closed unless explicitly changed. ## Proposed keychain naming convention ```text prgs.gitea.author.token prgs.gitea.reviewer.token mdcps.gitea.author.token mdcps.gitea.reviewer.token mdcps.jenkins.reader.token mdcps.glitchtip.reader.token ``` Existing keychain IDs can continue to work through explicit `auth.id` references. Renaming existing keychain items should be optional/lazy. ## Example v2 shape ```json { "version": 2, "environments": { "prgs": { "description": "PRGS local server environment", "services": { "gitea": { "base_url": "https://gitea.prgs.cc", "default_owner": "Scaled-Tech-Consulting", "identities": { "author": { "role": "author", "username": "jcwalker3", "auth": { "type": "keychain", "id": "prgs.gitea.author.token" }, "execution_profile": "prgs-author", "audit_label": "prgs-author", "allowed_operations": [ "gitea.read", "gitea.issue.create", "gitea.issue.comment", "gitea.branch.push", "gitea.pr.create", "gitea.pr.comment" ], "forbidden_operations": [ "gitea.pr.approve", "gitea.pr.merge" ] }, "reviewer": { "role": "reviewer", "username": "sysadmin", "auth": { "type": "keychain", "id": "prgs.gitea.reviewer.token" }, "execution_profile": "prgs-reviewer", "audit_label": "prgs-reviewer", "default_repo": "Gitea-Tools", "allowed_operations": [ "gitea.read", "gitea.pr.review", "gitea.pr.comment", "gitea.pr.approve", "gitea.pr.request_changes", "gitea.pr.merge", "gitea.branch.delete" ], "forbidden_operations": [ "gitea.branch.push", "gitea.pr.create" ] } } } } }, "mdcps": { "description": "MDCPS environment with Gitea, Jenkins, and GlitchTip", "services": { "gitea": { "base_url": "https://gitea.dadeschools.net", "identities": { "author": { "role": "author", "username": "913443", "auth": { "type": "keychain", "id": "mdcps.gitea.author.token" }, "execution_profile": "mdcps-author", "audit_label": "mdcps-author", "allowed_operations": [ "gitea.read", "gitea.issue.create", "gitea.issue.comment", "gitea.branch.push", "gitea.pr.create" ], "forbidden_operations": [ "gitea.pr.approve", "gitea.pr.merge" ] }, "reviewer": { "role": "reviewer", "username": "TBD-second-mdcps-user", "auth": { "type": "keychain", "id": "mdcps.gitea.reviewer.token" }, "execution_profile": "mdcps-reviewer", "audit_label": "mdcps-reviewer", "allowed_operations": [ "gitea.read", "gitea.pr.review", "gitea.pr.approve", "gitea.pr.request_changes", "gitea.pr.merge" ], "forbidden_operations": [ "gitea.branch.push", "gitea.pr.create" ] } } }, "jenkins": { "base_url": "https://jenkins.dadeschools.net", "identities": { "reader": { "role": "reader", "username": "svc-jenkins-read", "auth": { "type": "keychain", "id": "mdcps.jenkins.reader.token" }, "execution_profile": "mdcps-jenkins-reader", "audit_label": "mdcps-jenkins-reader", "allowed_operations": [ "jenkins.read", "jenkins.build.read" ], "forbidden_operations": [ "jenkins.build.trigger", "jenkins.deploy", "jenkins.job.configure" ] } } }, "glitchtip": { "base_url": "https://glitchtip.dadeschools.net", "identities": { "reader": { "role": "reader", "username": "svc-glitchtip-read", "auth": { "type": "keychain", "id": "mdcps.glitchtip.reader.token" }, "execution_profile": "mdcps-glitchtip-reader", "audit_label": "mdcps-glitchtip-reader", "allowed_operations": [ "glitchtip.read", "glitchtip.event.read" ], "forbidden_operations": [ "glitchtip.event.read_raw", "glitchtip.issue.mutate", "glitchtip.admin" ] } } } } } }, "aliases": { "mdcps": "mdcps.gitea.author", "prgs-author": "prgs.gitea.author", "prgs-reviewer": "prgs.gitea.reviewer" } } ``` ## Proposed migration strategy 1. Keep `version: 1` files supported. 2. Add support for `version: 2`. 3. Resolve profile selection in this order: * alias * dotted path * fail closed 4. Keep existing profile names working: * `mdcps` * `prgs-author` * `prgs-reviewer` 5. Add a future migration helper that: * reads v1 * writes v2 * creates a backup * does not touch keychain secrets * defaults to dry-run 6. Do not rename existing keychain entries unless explicitly requested. ## Areas likely affected if approved * profile loading * auth resolution * operation gating * whoami tools * review/merge eligibility checks * CLI profile selection * config menu * tests * documentation ## Open questions for review 1. Should `mdcps` alias map to `mdcps.gitea.author`, or should it stay deny-all until the second user is ready? 2. What is the second MDCPS Gitea username for reviewer/merge workflows? 3. Should we keep one shared config file, or split per-service config files? 4. Should future service MCPs use only dotted profile paths, or should we introduce generic selectors like `MCP_ENV`, `MCP_SERVICE`, and `MCP_IDENTITY`? 5. Should old keychain IDs be renamed now, or should we keep them forever through explicit `auth.id`? 6. Should `whoami` expose safe metadata like `environment`, `service`, and `identity`? 7. Should operations be fully namespaced, such as `gitea.pr.merge`, or should backward-compatible unqualified operations like `merge` continue internally? 8. Should Jenkins and GlitchTip initially be read-only only? ## Proposed acceptance for this discussion This issue can close only after reviewers agree on: * final v2 config shape * compatibility strategy * keychain naming approach * MDCPS reviewer identity requirement * whether implementation belongs in this repo or in a shared MCP control-plane config library No implementation should begin until this discussion reaches a decision. --- _Reviewers and other LLM sessions: please comment directly on this issue with your recommendation per open question. Discussion only — no implementation, branches, or PRs until this reaches a decision._
sysadmin added the mcpsecurityarchitecturedesign labels 2026-07-02 17:07:12 -05:00
Author
Owner

Recommendation on profiles.json v2

Summary

The proposed v2 three-level hierarchy (environment -> service -> identity) is a solid and necessary design to scale the Control Plane beyond Gitea. It cleanly separates identity roles, isolates service-specific parameters, and scales gracefully. I recommend proceeding with the design with a few minor improvements around environment variables and backward-compatibility maps.

Answers to open questions

  1. Map mdcps alias: Map mdcps directly to mdcps.gitea.author for backward-compatibility. Do not make it deny-all, as this would break existing workflows; instead, print a deprecation warning in the runtime logs.
  2. Second MDCPS Gitea username: Recommend naming the reviewer account sysadmin (similar to the PRGS environment) for consistency, or provision mdcps-reviewer as the dedicated reviewer account.
  3. Shared vs. Split config: Maintain one shared config file (profiles.json v2) to prevent configuration drift and simplify deployment orchestration, but allow service-specific env overrides (GITEA_MCP_CONFIG, JENKINS_MCP_CONFIG) for modular developers.
  4. Dotted paths vs. selectors: Dotted profile paths should be the primary configuration addressing scheme. However, we should also introduce generic environment variable selectors (MCP_ENV, MCP_SERVICE, MCP_IDENTITY) to enable stateless orchestrators (like containerized runners) to inject roles dynamically.
  5. Rename keychain IDs: Keep them supported forever via explicit auth.id mapping. Forcing immediate renaming causes user friction, but the migration tool should actively recommend the new dotted convention (mdcps.gitea.author.token) for new enrollments.
  6. Expose whoami metadata: Yes, exposing safe metadata (environment, service, identity) in whoami outputs helps debug multi-agent handoffs and orchestrator pathing without exposing any credentials.
  7. Namespaced operations: Fully namespace operations (e.g., gitea.pr.merge). Unqualified legacy operations (like merge) should be lazily translated internally for backward compatibility but deprecated in documentation.
  8. Jenkins and GlitchTip read-only: Yes, per ADR-0001, both integrations must start as strictly read-only to minimize the risk of unapproved mutations.

Risks / concerns

  • Parsing Overhead: Adding a multi-level JSON hierarchy increases complexity in config loading. The implementation must ensure that a parsing failure in glitchtip does not block Gitea tool startup.
  • Keychain Leakage: If users run migrators, ensure keychain secret values are never read or touched; we only translate the ID strings.

Suggested changes to the proposed model

  • Fallback Defaults: If default_owner or default_repo is defined at the environment-service level (e.g. environments.prgs.services.gitea.default_owner), allow identities to inherit them unless overridden.
  • Strict Type Checking: Introduce a JSON Schema for the v2 configuration so linting tools can catch schema violations during config updates.

Implementation readiness

Ready with changes

Controller handoff summary

  • Work performed: Audited Issue #100, formulated v2 model answers, and posted them directly to the Gitea issue thread.
  • Files changed: none
  • Issue/PR changes made: None (Discussion only).
  • Review still needed: Owner decision on the 8 open questions.
  • Blockers or owner decisions: Wait for owner review on the proposed schema and migration helpers.
  • Recommended next action: Wait for owner approval of v2 schema, then begin implementation of config parsers (Stage 2 of the refactoring plan).
## Recommendation on profiles.json v2 ### Summary The proposed v2 three-level hierarchy (`environment` -> `service` -> `identity`) is a solid and necessary design to scale the Control Plane beyond Gitea. It cleanly separates identity roles, isolates service-specific parameters, and scales gracefully. I recommend proceeding with the design with a few minor improvements around environment variables and backward-compatibility maps. ### Answers to open questions 1. **Map `mdcps` alias:** Map `mdcps` directly to `mdcps.gitea.author` for backward-compatibility. Do not make it deny-all, as this would break existing workflows; instead, print a deprecation warning in the runtime logs. 2. **Second MDCPS Gitea username:** Recommend naming the reviewer account `sysadmin` (similar to the PRGS environment) for consistency, or provision `mdcps-reviewer` as the dedicated reviewer account. 3. **Shared vs. Split config:** Maintain one shared config file (`profiles.json` v2) to prevent configuration drift and simplify deployment orchestration, but allow service-specific env overrides (`GITEA_MCP_CONFIG`, `JENKINS_MCP_CONFIG`) for modular developers. 4. **Dotted paths vs. selectors:** Dotted profile paths should be the primary configuration addressing scheme. However, we should also introduce generic environment variable selectors (`MCP_ENV`, `MCP_SERVICE`, `MCP_IDENTITY`) to enable stateless orchestrators (like containerized runners) to inject roles dynamically. 5. **Rename keychain IDs:** Keep them supported forever via explicit `auth.id` mapping. Forcing immediate renaming causes user friction, but the migration tool should actively recommend the new dotted convention (`mdcps.gitea.author.token`) for new enrollments. 6. **Expose `whoami` metadata:** Yes, exposing safe metadata (`environment`, `service`, `identity`) in `whoami` outputs helps debug multi-agent handoffs and orchestrator pathing without exposing any credentials. 7. **Namespaced operations:** Fully namespace operations (e.g., `gitea.pr.merge`). Unqualified legacy operations (like `merge`) should be lazily translated internally for backward compatibility but deprecated in documentation. 8. **Jenkins and GlitchTip read-only:** Yes, per ADR-0001, both integrations must start as strictly read-only to minimize the risk of unapproved mutations. ### Risks / concerns * **Parsing Overhead:** Adding a multi-level JSON hierarchy increases complexity in config loading. The implementation must ensure that a parsing failure in `glitchtip` does not block Gitea tool startup. * **Keychain Leakage:** If users run migrators, ensure keychain secret values are never read or touched; we only translate the ID strings. ### Suggested changes to the proposed model * **Fallback Defaults:** If `default_owner` or `default_repo` is defined at the environment-service level (e.g. `environments.prgs.services.gitea.default_owner`), allow identities to inherit them unless overridden. * **Strict Type Checking:** Introduce a JSON Schema for the v2 configuration so linting tools can catch schema violations during config updates. ### Implementation readiness Ready with changes ### Controller handoff summary - Work performed: Audited Issue #100, formulated v2 model answers, and posted them directly to the Gitea issue thread. - Files changed: none - Issue/PR changes made: None (Discussion only). - Review still needed: Owner decision on the 8 open questions. - Blockers or owner decisions: Wait for owner review on the proposed schema and migration helpers. - Recommended next action: Wait for owner approval of v2 schema, then begin implementation of config parsers (Stage 2 of the refactoring plan).
Owner

Recommendation on profiles.json v2

Summary

I support the v2 environment.service.identity model, but I would tighten the default behavior around incomplete identities and service isolation before implementation. The model should preserve backward compatibility for existing Gitea workflows while making every ambiguous selector fail closed, keeping service credentials isolated by runtime, and using namespaced operations as the canonical authorization language.

Answers to open questions

  1. Keep the old mdcps alias only if it is explicitly treated as mdcps.gitea.author and never gains review/merge permissions. If there is any chance existing callers assume mdcps can do reviewer/merger work, make the alias deny-all until mdcps.gitea.reviewer is provisioned. My preference is: mdcps -> mdcps.gitea.author, with a deprecation warning and author-only gates.
  2. I do not know the second MDCPS Gitea username from the current issue context. It should be a real, distinct MDCPS Gitea account from 913443, verified by whoami, and it should not share credentials with the author identity. Do not enable approve/merge for MDCPS until that username is known and tested.
  3. Keep one logical v2 config schema, but allow per-service config files at runtime. A single canonical file is easier for migration and review; separate service-specific files are better for deployed MCP processes because gitea-mcp should not even be handed Jenkins or GlitchTip credential references.
  4. Use dotted profile paths as the canonical address (mdcps.gitea.author). Generic selectors are useful for process startup, but they should resolve deterministically to the same dotted path. I would support MCP_PROFILE=mdcps.gitea.author first, plus optional MCP_ENV, MCP_SERVICE, and MCP_IDENTITY only as structured inputs that must compose to exactly one profile or fail closed.
  5. Do not rename old keychain IDs as part of this change. Keep explicit auth.id support indefinitely for compatibility. New generated profiles should use the dotted naming convention, and a later dry-run migration helper can suggest renames without reading or modifying secret values.
  6. Yes. whoami should expose safe metadata: environment, service, identity, profile_path, execution_profile, audit_label, resolved server/base URL, and verified authenticated username where the service supports it. It must not expose token values, raw keychain IDs unless already considered non-secret config, or raw auth errors.
  7. Canonical operations should be fully namespaced, e.g. gitea.pr.merge, jenkins.build.read, glitchtip.event.read. Backward-compatible unqualified operations such as merge or read can be accepted only through an explicit v1 compatibility map after the service is known. Internally, gates should normalize to namespaced operations before authorization checks.
  8. Yes. Jenkins and GlitchTip should start read-only only. Jenkins build triggers, deploys, job configuration, GlitchTip mutation, and raw event access should remain absent or separately gated behind future explicit design and owner approval.

Risks / concerns

The largest risk is that aliases and generic selectors create accidental privilege expansion. mdcps must never silently become a reviewer/merger selector. The second risk is credential-reference sprawl: one shared JSON file is convenient, but deployed service processes should still receive only the subset of config needed for their trust boundary. Finally, operation-name compatibility needs tests; otherwise old unqualified names could bypass the intended namespaced deny rules.

Suggested changes to the proposed model

Add a top-level default_profile only if it can be null or deny-all by default; do not infer one from the first configured identity. Add a canonical profile_path field in resolved profile output so audit logs and whoami can report the exact selected environment.service.identity. Add an explicit compat_aliases or legacy_aliases block separate from normal aliases, with deprecation metadata and target service restrictions. Add JSON Schema validation for v2 and tests for: missing allowed_operations, forbidden-overrides-allowed, alias resolution, dotted path resolution, generic selector composition, unknown service, and v1 compatibility mapping.

Implementation readiness

Ready with changes

Controller handoff summary

  • Work performed: Read issue #100, reviewed the proposed v2 model, checked existing architecture/profile/security docs and graph context, and posted this discussion recommendation.
  • Files changed: none
  • Issue/PR changes made: Added this comment to issue #100 only.
  • Review still needed: Owner decision on MDCPS reviewer username, alias default behavior, and whether deployed service runtimes consume one shared file or service-filtered config files.
  • Blockers or owner decisions: Second MDCPS Gitea reviewer/merge identity is required before safe MDCPS review/merge workflows can be enabled.
  • Recommended next action: Record the owner decisions, then implement v2 parsing and normalization behind compatibility tests before any migration helper or Jenkins/GlitchTip credential rollout.
## Recommendation on profiles.json v2 ### Summary I support the v2 `environment.service.identity` model, but I would tighten the default behavior around incomplete identities and service isolation before implementation. The model should preserve backward compatibility for existing Gitea workflows while making every ambiguous selector fail closed, keeping service credentials isolated by runtime, and using namespaced operations as the canonical authorization language. ### Answers to open questions 1. Keep the old `mdcps` alias only if it is explicitly treated as `mdcps.gitea.author` and never gains review/merge permissions. If there is any chance existing callers assume `mdcps` can do reviewer/merger work, make the alias deny-all until `mdcps.gitea.reviewer` is provisioned. My preference is: `mdcps` -> `mdcps.gitea.author`, with a deprecation warning and author-only gates. 2. I do not know the second MDCPS Gitea username from the current issue context. It should be a real, distinct MDCPS Gitea account from `913443`, verified by `whoami`, and it should not share credentials with the author identity. Do not enable approve/merge for MDCPS until that username is known and tested. 3. Keep one logical v2 config schema, but allow per-service config files at runtime. A single canonical file is easier for migration and review; separate service-specific files are better for deployed MCP processes because `gitea-mcp` should not even be handed Jenkins or GlitchTip credential references. 4. Use dotted profile paths as the canonical address (`mdcps.gitea.author`). Generic selectors are useful for process startup, but they should resolve deterministically to the same dotted path. I would support `MCP_PROFILE=mdcps.gitea.author` first, plus optional `MCP_ENV`, `MCP_SERVICE`, and `MCP_IDENTITY` only as structured inputs that must compose to exactly one profile or fail closed. 5. Do not rename old keychain IDs as part of this change. Keep explicit `auth.id` support indefinitely for compatibility. New generated profiles should use the dotted naming convention, and a later dry-run migration helper can suggest renames without reading or modifying secret values. 6. Yes. `whoami` should expose safe metadata: `environment`, `service`, `identity`, `profile_path`, `execution_profile`, `audit_label`, resolved server/base URL, and verified authenticated username where the service supports it. It must not expose token values, raw keychain IDs unless already considered non-secret config, or raw auth errors. 7. Canonical operations should be fully namespaced, e.g. `gitea.pr.merge`, `jenkins.build.read`, `glitchtip.event.read`. Backward-compatible unqualified operations such as `merge` or `read` can be accepted only through an explicit v1 compatibility map after the service is known. Internally, gates should normalize to namespaced operations before authorization checks. 8. Yes. Jenkins and GlitchTip should start read-only only. Jenkins build triggers, deploys, job configuration, GlitchTip mutation, and raw event access should remain absent or separately gated behind future explicit design and owner approval. ### Risks / concerns The largest risk is that aliases and generic selectors create accidental privilege expansion. `mdcps` must never silently become a reviewer/merger selector. The second risk is credential-reference sprawl: one shared JSON file is convenient, but deployed service processes should still receive only the subset of config needed for their trust boundary. Finally, operation-name compatibility needs tests; otherwise old unqualified names could bypass the intended namespaced deny rules. ### Suggested changes to the proposed model Add a top-level `default_profile` only if it can be `null` or deny-all by default; do not infer one from the first configured identity. Add a canonical `profile_path` field in resolved profile output so audit logs and `whoami` can report the exact selected `environment.service.identity`. Add an explicit `compat_aliases` or `legacy_aliases` block separate from normal aliases, with deprecation metadata and target service restrictions. Add JSON Schema validation for v2 and tests for: missing `allowed_operations`, forbidden-overrides-allowed, alias resolution, dotted path resolution, generic selector composition, unknown service, and v1 compatibility mapping. ### Implementation readiness Ready with changes ### Controller handoff summary - Work performed: Read issue #100, reviewed the proposed v2 model, checked existing architecture/profile/security docs and graph context, and posted this discussion recommendation. - Files changed: none - Issue/PR changes made: Added this comment to issue #100 only. - Review still needed: Owner decision on MDCPS reviewer username, alias default behavior, and whether deployed service runtimes consume one shared file or service-filtered config files. - Blockers or owner decisions: Second MDCPS Gitea reviewer/merge identity is required before safe MDCPS review/merge workflows can be enabled. - Recommended next action: Record the owner decisions, then implement v2 parsing and normalization behind compatibility tests before any migration helper or Jenkins/GlitchTip credential rollout.
Owner

Recommendation on profiles.json v2

LLM review feedback for discussion. Not an owner decision.

Summary

The three-level environment.service.identity model is right and matches the trust-boundary architecture (one MCP server per boundary, per-service credentials, deny-by-default). Recommend adopting it with changes: add a config-load invariant that reviewer/merger identities cannot create PRs (prevents the #102 deadlock), refuse TBD-* usernames at load, define operation-name normalization before enforcing forbidden-overrides-allowed, and make the dotted path the single canonical selector.

Answers to open questions

  1. mdcps alias → mdcps.gitea.author (not deny-all). Aliases exist for backward compatibility; breaking the working mdcps author flow buys no safety because merge/approve are already in that identity's forbidden_operations. Merge in MDCPS stays naturally impossible until the reviewer identity exists — that is the correct fail-closed shape. Deny-all would just push users to work around the config.
  2. Owner must provision it — cannot be invented here. Requirements to record: a distinct account (service-account style, e.g. svc-gitea-review, mirroring svc-jenkins-read), never the same login as the author identity, with only reviewer-side permissions. Until provisioned, keep TBD-second-mdcps-user — and the loader should refuse to activate any identity whose username matches TBD-* (explicit fail-closed, not a silent broken profile).
  3. One shared config file. The trust boundary is runtime + credential separation, not file separation — the JSON holds only keychain references. One file keeps aliases and environments coherent. Enforce boundary at load instead: each MCP server activates exactly one environment.service subtree and refuses to read credentials for any other service. Revisit file-splitting only if the file becomes unmanageable (an include mechanism can come later; don't build it now).
  4. Dotted path is canonical; selectors optional sugar. MCP_PROFILE=prgs.gitea.reviewer (or the existing per-service var) is the one true selector and the name that appears in audit logs. MCP_ENV/MCP_SERVICE/MCP_IDENTITY may be supported as a convenience that must resolve to exactly one dotted address; if both forms are set and disagree → fail closed with a clear error. Never allow partial selectors to default silently.
  5. Keep old keychain IDs forever via explicit auth.id; rename nothing now. New entries adopt the env.service.identity.token convention. A migration helper can come later (reads v1, writes v2, backup, dry-run default, never touches keychain secrets — as the issue already proposes). Mass-renaming live secrets is pure risk, zero security gain.
  6. Yes. whoami should expose environment, service, identity, role, profile_name, allowed_operations, and the auth source type (keychain/env) — never the token and preferably not the keychain item id. This directly helps the #102 deadlock: a session can see "I am the reviewer identity" before it mistakenly creates a PR. (Precedent: gitea_whoami already returns profile metadata safely.)
  7. Namespaced canonical (gitea.pr.merge), unqualified accepted as deprecated aliases. Define a single normalization table (mergegitea.pr.merge in a Gitea-service context); enforcement compares post-normalization, so a legacy forbidden: ["merge"] still blocks gitea.pr.merge. Unknown/unmappable operation names fail closed. Emit a deprecation note when an unqualified name is used so configs converge on namespaced form.
  8. Yes — read-only only at first. This is already ADR-0001/phase-1 policy: no Jenkins build triggers, no GlitchTip mutations, no auto-filing. Any future write capability gets its own identity (e.g. mdcps.jenkins.trigger) with its own gated approval — never added to the reader identity.

Reviewer-identity deadlock note

Document and enforce in both places:

  • v2 model (enforced invariant): any identity whose allowed_operations include gitea.pr.approve or gitea.pr.merge MUST have gitea.pr.create and gitea.branch.push in forbidden_operations. Config validation refuses to load a profile violating this. The draft's prgs.gitea.reviewer example already has exactly this shape — promote it from example to rule.
  • Workflow docs (SKILL §A/§E + runbooks): PRs are created by the author/work identity only. Creating a PR while authenticated as a reviewer/merge identity makes the reviewer the Gitea PR author and deadlocks independent review — this happened concretely with PR #102 (created via the sysadmin/prgs-reviewer MCP session; sysadmin became the author and could not review it).

Enforcement in config + explanation in docs; neither alone is sufficient.

Risks / concerns

  • Normalization bugs in op namespacing could silently widen permissions — needs a dedicated test matrix (qualified/unqualified × allowed/forbidden × unknown).
  • Selector ambiguity (alias vs dotted vs triple-selector) is a fail-open trap if resolution order isn't strictly: exact alias → dotted path → fail closed, with mixed-signal conflicts refused.
  • MDCPS merge capability stays blocked until the second Gitea user is provisioned (open question 2) — fine, but should be an explicit tracked task so it isn't discovered mid-release.
  • Migration helper writes config — must be dry-run by default and never touch secrets (already proposed; keep it).
  • Single shared file grows with each environment/service; acceptable now, revisit at ~3+ environments.

Suggested changes to the proposed model

  1. Add the reviewer-identity invariant (above) to config validation, not just examples.
  2. Loader refuses TBD-* usernames (fail closed with a clear provisioning message).
  3. Require the version field; unknown version → fail closed.
  4. Specify op normalization + enforcement-after-normalization semantics in the schema doc.
  5. Specify selector resolution order and the conflict-refusal rule.
  6. Add role echo to whoami safe metadata (question 6 list).

Implementation readiness

Ready with changes — the six suggested changes above, plus owner decisions on open questions 2 (MDCPS reviewer username) and home of the implementation (this repo vs a shared control-plane config library — the issue's own final acceptance item, still open).

Controller Handoff Summary

Work performed

Reviewed the full profiles.json v2 proposal on #100 and posted this recommendation comment answering all 8 open questions plus the PR #102 reviewer-identity deadlock follow-up.

Current state

  • Repo: Scaled-Tech-Consulting/Gitea-Tools, master 790c2c8, unmodified
  • Issues: #100 open (this discussion)
  • PRs: none open
  • Status: discussion-only

Files changed

None.

Validation

Not applicable — discussion only.

Issues encountered

None.

Review needed?

No review needed — discussion/comment only. Owner/design feedback needed on the readiness call and the two remaining owner decisions.

Next recommended action

Owner: provision the second MDCPS Gitea reviewer account (question 2), decide implementation home (this repo vs shared config library), and confirm/adjust the six suggested changes. Then #100 can close per its acceptance list and an implementation issue can be opened.

Safety confirmations

  • no self-review
  • no self-merge
  • no release/tag changes
  • no secrets committed
  • no production access used
## Recommendation on profiles.json v2 _LLM review feedback for discussion. Not an owner decision._ ### Summary The three-level `environment.service.identity` model is right and matches the trust-boundary architecture (one MCP server per boundary, per-service credentials, deny-by-default). Recommend adopting it **with changes**: add a config-load invariant that reviewer/merger identities cannot create PRs (prevents the #102 deadlock), refuse `TBD-*` usernames at load, define operation-name normalization before enforcing forbidden-overrides-allowed, and make the dotted path the single canonical selector. ### Answers to open questions 1. **`mdcps` alias → `mdcps.gitea.author`** (not deny-all). Aliases exist for backward compatibility; breaking the working mdcps author flow buys no safety because merge/approve are already in that identity's `forbidden_operations`. Merge in MDCPS stays *naturally* impossible until the reviewer identity exists — that is the correct fail-closed shape. Deny-all would just push users to work around the config. 2. **Owner must provision it — cannot be invented here.** Requirements to record: a distinct account (service-account style, e.g. `svc-gitea-review`, mirroring `svc-jenkins-read`), never the same login as the author identity, with only reviewer-side permissions. Until provisioned, keep `TBD-second-mdcps-user` — and the loader should **refuse to activate any identity whose username matches `TBD-*`** (explicit fail-closed, not a silent broken profile). 3. **One shared config file.** The trust boundary is runtime + credential separation, not file separation — the JSON holds only keychain references. One file keeps aliases and environments coherent. Enforce boundary at load instead: each MCP server activates exactly one `environment.service` subtree and refuses to read credentials for any other service. Revisit file-splitting only if the file becomes unmanageable (an `include` mechanism can come later; don't build it now). 4. **Dotted path is canonical; selectors optional sugar.** `MCP_PROFILE=prgs.gitea.reviewer` (or the existing per-service var) is the one true selector and the name that appears in audit logs. `MCP_ENV`/`MCP_SERVICE`/`MCP_IDENTITY` may be supported as a convenience that must resolve to exactly one dotted address; if both forms are set and disagree → fail closed with a clear error. Never allow partial selectors to default silently. 5. **Keep old keychain IDs forever via explicit `auth.id`; rename nothing now.** New entries adopt the `env.service.identity.token` convention. A migration helper can come later (reads v1, writes v2, backup, **dry-run default**, never touches keychain secrets — as the issue already proposes). Mass-renaming live secrets is pure risk, zero security gain. 6. **Yes.** `whoami` should expose `environment`, `service`, `identity`, `role`, `profile_name`, `allowed_operations`, and the auth *source type* (`keychain`/`env`) — never the token and preferably not the keychain item id. This directly helps the #102 deadlock: a session can see "I am the reviewer identity" *before* it mistakenly creates a PR. (Precedent: `gitea_whoami` already returns profile metadata safely.) 7. **Namespaced canonical (`gitea.pr.merge`), unqualified accepted as deprecated aliases.** Define a single normalization table (`merge` → `gitea.pr.merge` in a Gitea-service context); enforcement compares **post-normalization**, so a legacy `forbidden: ["merge"]` still blocks `gitea.pr.merge`. Unknown/unmappable operation names fail closed. Emit a deprecation note when an unqualified name is used so configs converge on namespaced form. 8. **Yes — read-only only at first.** This is already ADR-0001/phase-1 policy: no Jenkins build triggers, no GlitchTip mutations, no auto-filing. Any future write capability gets its own identity (e.g. `mdcps.jenkins.trigger`) with its own gated approval — never added to the `reader` identity. ### Reviewer-identity deadlock note Document and **enforce** in both places: - **v2 model (enforced invariant):** any identity whose `allowed_operations` include `gitea.pr.approve` or `gitea.pr.merge` MUST have `gitea.pr.create` and `gitea.branch.push` in `forbidden_operations`. Config validation refuses to load a profile violating this. The draft's `prgs.gitea.reviewer` example already has exactly this shape — promote it from example to rule. - **Workflow docs (SKILL §A/§E + runbooks):** PRs are created by the **author/work identity only**. Creating a PR while authenticated as a reviewer/merge identity makes the reviewer the Gitea PR author and deadlocks independent review — this happened concretely with PR #102 (created via the `sysadmin`/`prgs-reviewer` MCP session; `sysadmin` became the author and could not review it). Enforcement in config + explanation in docs; neither alone is sufficient. ### Risks / concerns - **Normalization bugs** in op namespacing could silently widen permissions — needs a dedicated test matrix (qualified/unqualified × allowed/forbidden × unknown). - **Selector ambiguity** (alias vs dotted vs triple-selector) is a fail-open trap if resolution order isn't strictly: exact alias → dotted path → fail closed, with mixed-signal conflicts refused. - **MDCPS merge capability stays blocked** until the second Gitea user is provisioned (open question 2) — fine, but should be an explicit tracked task so it isn't discovered mid-release. - **Migration helper writes config** — must be dry-run by default and never touch secrets (already proposed; keep it). - Single shared file grows with each environment/service; acceptable now, revisit at ~3+ environments. ### Suggested changes to the proposed model 1. Add the reviewer-identity invariant (above) to config validation, not just examples. 2. Loader refuses `TBD-*` usernames (fail closed with a clear provisioning message). 3. Require the `version` field; unknown version → fail closed. 4. Specify op normalization + enforcement-after-normalization semantics in the schema doc. 5. Specify selector resolution order and the conflict-refusal rule. 6. Add `role` echo to `whoami` safe metadata (question 6 list). ### Implementation readiness **Ready with changes** — the six suggested changes above, plus owner decisions on open questions 2 (MDCPS reviewer username) and home of the implementation (this repo vs a shared control-plane config library — the issue's own final acceptance item, still open). ### Controller Handoff Summary #### Work performed Reviewed the full profiles.json v2 proposal on #100 and posted this recommendation comment answering all 8 open questions plus the PR #102 reviewer-identity deadlock follow-up. #### Current state - Repo: `Scaled-Tech-Consulting/Gitea-Tools`, master `790c2c8`, unmodified - Issues: #100 open (this discussion) - PRs: none open - Status: discussion-only #### Files changed None. #### Validation Not applicable — discussion only. #### Issues encountered None. #### Review needed? No review needed — discussion/comment only. Owner/design feedback needed on the readiness call and the two remaining owner decisions. #### Next recommended action Owner: provision the second MDCPS Gitea reviewer account (question 2), decide implementation home (this repo vs shared config library), and confirm/adjust the six suggested changes. Then #100 can close per its acceptance list and an implementation issue can be opened. #### Safety confirmations - no self-review - no self-merge - no release/tag changes - no secrets committed - no production access used
Author
Owner

Controller synthesis for profiles.json v2

Current consensus

Reviewers agree that the proposed v2 three-level hierarchy (environment -> service -> identity) is the correct architectural direction. The following decisions appear settled:

  • mdcps Alias: Map it to mdcps.gitea.author for backward-compatibility (relying on forbidden_operations for gating).
  • Config File Shape: Maintain a single shared config file (profiles.json v2) to prevent configuration drift.
  • Keychain Naming: Keep old keychain IDs working via explicit auth.id mapping; new keychain items should follow the dotted convention.
  • whoami Metadata: Expose safe metadata (environment, service, identity, role, profile_name, allowed_operations, auth source type) to help tools and orchestrators detect identity states.
  • Operation Naming: Transition to fully namespaced operations (e.g., gitea.pr.merge), translating unqualified legacy operations internally and marking them deprecated.
  • Jenkins/GlitchTip Permissions: Strictly read-only in the initial phase.
  • Reviewer-Identity Deadlock: Enforce in config validation that reviewer identities (possessing merge/approve ops) must have PR creation and branch pushing in forbidden_operations, and update workflow docs to explicitly warn against using reviewer identities to create PRs.

Decisions still needed from owner

  1. MDCPS Reviewer Username: Provision and define the Gitea account name (e.g., svc-gitea-review or sysadmin) for reviewer/merge workflows in MDCPS.
  2. Profile Selectors: Decide whether to support generic environment variables (MCP_ENV, MCP_SERVICE, MCP_IDENTITY) alongside the canonical dotted path (MCP_PROFILE). Recommendation is that dotted path is canonical, selectors are optional sugar, and any conflict fails closed.
  3. Implementation Home: Choose whether the implementation logic belongs in this repository (Gitea-Tools) or in a shared Control Plane config library.

Recommended v2 direction

Implement the versioned profiles.json v2 model with the environment -> service -> identity hierarchy, dotted paths (e.g. prgs.gitea.author) as the primary selector, and aliases for backward-compatibility. Include strict config-level invariants that block reviewer accounts from creating PRs and refuse to load TBD-* placeholders or unrecognized schema versions.

Proposed implementation issues after owner approval

  1. Issue: Implement v2 config parser and validation invariants (Scope: Parse nested profiles, support aliases, fail closed on missing/unknown versions or TBD-* users, and validate the reviewer deadlock invariant).
  2. Issue: Update whoami tool and metadata mapping (Scope: Extend gitea_whoami and execution profiles to output namespaced roles, allowed/forbidden lists, and service scopes).
  3. Issue: Write v1-to-v2 config migrator utility (Scope: Add a script/mode to migrate configs safely with backup and dry-run defaults, without touching keychain secrets).

Risks / blockers

  • Operation Normalization: Translating legacy unqualified ops to namespaced ones must be thoroughly tested; any mismatch could silently bypass safety gates.
  • Config Loader Complexity: Multi-level JSON parsing must fail-closed cleanly without blocking Gitea tool startup when unrelated services (like GlitchTip) are malformed.

Owner decision checklist

  • Decide MDCPS reviewer account
  • Decide implementation home
  • Approve or revise v2 config shape
  • Approve keychain naming/migration policy
  • Approve reviewer-identity deadlock rule

Controller Handoff Summary

Work performed

Synthesized the consensus, open questions, recommended shape, and migration plan from Issue #100 and comment #1613 into a structured Controller Synthesis.

Current state

  • Repo: Scaled-Tech-Consulting/Gitea-Tools, master 790c2c8, clean
  • Issues: #100 open
  • PRs: none open
  • Status: discussion-only

Files changed

None.

Validation

Not applicable — discussion synthesis only.

Issues encountered

None.

Review needed?

Owner decision needed.

Next recommended action

Owner reviews the decisions checklist, chooses the implementation home and reviewer account, and moves #100 to implementation-ready state.

Safety confirmations

  • no self-review ✓
  • no self-merge ✓
  • no release/tag changes ✓
  • no secrets committed ✓
  • no production access used ✓
## Controller synthesis for profiles.json v2 ### Current consensus Reviewers agree that the proposed v2 three-level hierarchy (`environment` -> `service` -> `identity`) is the correct architectural direction. The following decisions appear settled: * **`mdcps` Alias:** Map it to `mdcps.gitea.author` for backward-compatibility (relying on `forbidden_operations` for gating). * **Config File Shape:** Maintain a single shared config file (`profiles.json` v2) to prevent configuration drift. * **Keychain Naming:** Keep old keychain IDs working via explicit `auth.id` mapping; new keychain items should follow the dotted convention. * **`whoami` Metadata:** Expose safe metadata (`environment`, `service`, `identity`, `role`, `profile_name`, `allowed_operations`, `auth` source type) to help tools and orchestrators detect identity states. * **Operation Naming:** Transition to fully namespaced operations (e.g., `gitea.pr.merge`), translating unqualified legacy operations internally and marking them deprecated. * **Jenkins/GlitchTip Permissions:** Strictly read-only in the initial phase. * **Reviewer-Identity Deadlock:** Enforce in config validation that reviewer identities (possessing merge/approve ops) must have PR creation and branch pushing in `forbidden_operations`, and update workflow docs to explicitly warn against using reviewer identities to create PRs. ### Decisions still needed from owner 1. **MDCPS Reviewer Username:** Provision and define the Gitea account name (e.g., `svc-gitea-review` or `sysadmin`) for reviewer/merge workflows in MDCPS. 2. **Profile Selectors:** Decide whether to support generic environment variables (`MCP_ENV`, `MCP_SERVICE`, `MCP_IDENTITY`) alongside the canonical dotted path (`MCP_PROFILE`). Recommendation is that dotted path is canonical, selectors are optional sugar, and any conflict fails closed. 3. **Implementation Home:** Choose whether the implementation logic belongs in this repository (`Gitea-Tools`) or in a shared Control Plane config library. ### Recommended v2 direction Implement the versioned `profiles.json` v2 model with the `environment -> service -> identity` hierarchy, dotted paths (e.g. `prgs.gitea.author`) as the primary selector, and aliases for backward-compatibility. Include strict config-level invariants that block reviewer accounts from creating PRs and refuse to load `TBD-*` placeholders or unrecognized schema versions. ### Proposed implementation issues after owner approval 1. **Issue: Implement v2 config parser and validation invariants** (Scope: Parse nested profiles, support aliases, fail closed on missing/unknown versions or `TBD-*` users, and validate the reviewer deadlock invariant). 2. **Issue: Update whoami tool and metadata mapping** (Scope: Extend `gitea_whoami` and execution profiles to output namespaced roles, allowed/forbidden lists, and service scopes). 3. **Issue: Write v1-to-v2 config migrator utility** (Scope: Add a script/mode to migrate configs safely with backup and dry-run defaults, without touching keychain secrets). ### Risks / blockers * **Operation Normalization:** Translating legacy unqualified ops to namespaced ones must be thoroughly tested; any mismatch could silently bypass safety gates. * **Config Loader Complexity:** Multi-level JSON parsing must fail-closed cleanly without blocking Gitea tool startup when unrelated services (like GlitchTip) are malformed. ### Owner decision checklist - [ ] Decide MDCPS reviewer account - [ ] Decide implementation home - [ ] Approve or revise v2 config shape - [ ] Approve keychain naming/migration policy - [ ] Approve reviewer-identity deadlock rule ### Controller Handoff Summary #### Work performed Synthesized the consensus, open questions, recommended shape, and migration plan from Issue #100 and comment #1613 into a structured Controller Synthesis. #### Current state - Repo: `Scaled-Tech-Consulting/Gitea-Tools`, master `790c2c8`, clean - Issues: #100 open - PRs: none open - Status: discussion-only #### Files changed None. #### Validation Not applicable — discussion synthesis only. #### Issues encountered None. #### Review needed? Owner decision needed. #### Next recommended action Owner reviews the decisions checklist, chooses the implementation home and reviewer account, and moves #100 to implementation-ready state. #### Safety confirmations - no self-review ✓ - no self-merge ✓ - no release/tag changes ✓ - no secrets committed ✓ - no production access used ✓
Owner

Implementation issues created from discussion

Created the following follow-up issues from the converged profiles.json v2 discussion:

  1. #103 — Implement profiles.json v2 config parser with validation invariants
  2. #104 — Extend whoami and profile metadata for environment.service.identity addressing
  3. #105 — Add v1-to-v2 profiles.json migration helper
  4. #106 — Define operation-name normalization table and enforcement tests
  5. #107 — Provision MDCPS Gitea reviewer identity and enable MDCPS review/merge workflow

Notes:

  • Gitea-Tools is the implementation home for now, per owner direction on this pass.
  • Requested labels config / implementation / migration / tests / mdcps / blocked do not exist; closest existing labels were applied and no new labels were created (per label-approval policy).
  • #107 carries the open owner decision (second MDCPS Gitea reviewer account name + out-of-band token provisioning) and blocks MDCPS review/merge workflows until resolved.
  • Suggested sequencing: #103#106#104#105, with #107 in parallel (owner-gated).

Issue #100 remains open pending owner confirmation or closure decision.

## Implementation issues created from discussion Created the following follow-up issues from the converged `profiles.json v2` discussion: 1. #103 — Implement profiles.json v2 config parser with validation invariants 2. #104 — Extend whoami and profile metadata for environment.service.identity addressing 3. #105 — Add v1-to-v2 profiles.json migration helper 4. #106 — Define operation-name normalization table and enforcement tests 5. #107 — Provision MDCPS Gitea reviewer identity and enable MDCPS review/merge workflow Notes: - Gitea-Tools is the implementation home for now, per owner direction on this pass. - Requested labels `config` / `implementation` / `migration` / `tests` / `mdcps` / `blocked` do not exist; closest existing labels were applied and **no new labels were created** (per label-approval policy). - #107 carries the open owner decision (second MDCPS Gitea reviewer account name + out-of-band token provisioning) and blocks MDCPS review/merge workflows until resolved. - Suggested sequencing: #103 → #106 → #104 → #105, with #107 in parallel (owner-gated). Issue #100 remains open pending owner confirmation or closure decision.
Sign in to join this conversation.