You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tooling.apache.org by "asf-tooling (via GitHub)" <gi...@apache.org> on 2026/05/08 20:43:47 UTC

Re: [I] Make email address selection in OpenPGP key generation clearer (tooling-trusted-releases)

asf-tooling commented on issue #1196:
URL: https://github.com/apache/tooling-trusted-releases/issues/1196#issuecomment-4409713554

   <!-- gofannon-issue-triage-bot v2 -->
   
   **Automated triage** — analyzed at `main@2da7807a`
   
   **Type:** `documentation`  •  **Classification:** `actionable`  •  **Confidence:** `high`
   **Application domain(s):** `cryptographic_keys`
   
   ### Summary
   The issue requests that the OpenPGP key addition page explain the email address criteria used to link a key to an ASF identity. Currently, the 'Add your OpenPGP key' page (atr/get/keys.py, `add()`) provides minimal guidance. The underlying logic in `atr/storage/writers/keys.py` (`__uids_asf_uid()`) resolves identity via @apache.org emails or LDAP-linked addresses from id.apache.org. @sbp noted the explanation should cover linked addresses, id.apache.org, and the permanent nature of the record.
   
   ### Where this lives in the code today
   
   #### `atr/get/keys.py` — `add` (lines 40-73)
   _needs modification_
   This is the GET handler that renders the 'Add your OpenPGP key' page - the primary location where email address selection criteria should be explained to the user.
   
   ```python
   @get.typed
   async def add(_session: web.Committer, _keys_add: Literal["keys/add"]) -> str:
       """
       URL: /keys/add
       Add a new public signing key to the user's account.
       """
       async with storage.write() as write:
           participant_of_committees = await write.participant_of_committees()
   
       committee_choices = [(c.key, c.display_name or c.key) for c in participant_of_committees]
   
       page = htm.Block()
       page.p[htm.a(".atr-back-link", href=util.as_url(keys))["← Back to Manage keys"],]
       page.div(".my-4")[
           htm.h1(".mb-4")["Add your OpenPGP key"],
           htm.p["Add your public key to use for signing release artifacts."],
       ]
       await form.render_block(
           page,
           model_cls=shared.keys.AddOpenPGPKeyForm,
           action=util.as_url(post.keys.add),
           submit_label="Add OpenPGP key",
           cancel_url=util.as_url(keys),
           defaults={
               "selected_committees": committee_choices,
           },
       )
   
       return await template.blank(
           "Add your OpenPGP key",
           content=page.collect(),
           description="Add your public signing key to your ATR account.",
           javascripts=["keys-add-toggle"],
       )
   ```
   
   #### `atr/storage/writers/keys.py` — `FoundationCommitter.__uids_asf_uid` (lines 554-583)
   _currently does this_
   This method implements the actual email resolution logic: first checks for @apache.org emails, then falls back to LDAP-linked email addresses. The UI explanation should reflect this logic.
   
   ```python
       def __uids_asf_uid(self, uids: list[str], ldap_data: dict[str, str]) -> str | None:
           # Test data
           test_key_uids = [
               "Apache Tooling (For test use only) <ap...@example.invalid>",
           ]
   
           if uids == test_key_uids:
               # Allow the test key
               if config.is_test_mode() and (self.__asf_uid == "test"):
                   # TODO: "test" is already an admin user
                   # But we want to narrow that down to only actions like this
                   # TODO: Add include_test: bool to user.is_admin?
                   return "test"
               if user.is_admin(self.__asf_uid):
                   return self.__asf_uid
   
           # Regular data
           emails = []
           for uid in uids:
               # This returns a lower case email address, whatever the case of the input
               if email := util.email_from_uid(uid):
                   if email.endswith("@apache.org"):
                       return email.removesuffix("@apache.org")
                   emails.append(email)
           # We did not find a direct @apache.org email address
           # Therefore, search cached LDAP data
           for email in emails:
               if email in ldap_data:
                   return ldap_data[email]
           return None
   ```
   
   #### `atr/post/keys.py` — `_openpgp_key_uid_warning` (lines 346-366)
   _currently does this_
   This provides after-the-fact warnings when UID resolution fails, but the issue requests proactive guidance before the user adds a key.
   
   ```python
   def _openpgp_key_uid_warning(key_model: sql.PublicSigningKey, current_asf_uid: str) -> htm.Element | None:
       fingerprint_upper = key_model.fingerprint.upper()
       if key_model.apache_uid is None:
           details_url = util.as_url(get.keys.details, fingerprint=key_model.fingerprint)
           return htm.p[
               f"OpenPGP key {fingerprint_upper} was uploaded and associated, but ATR could not determine an ASF UID "
               "from the key user IDs. ",
               htm.a(href=details_url)["Review key details"],
               ".",
           ]
   
       if key_model.apache_uid.lower() != current_asf_uid.lower():
           details_url = util.as_url(get.keys.details, fingerprint=key_model.fingerprint)
           return htm.p[
               f"OpenPGP key {fingerprint_upper} was uploaded and associated, but it appears to belong to ASF UID "
               f"{key_model.apache_uid}, not {current_asf_uid}. ",
               htm.a(href=details_url)["Review key details"],
               ".",
           ]
   
       return None
   ```
   
   ### Proposed approach
   Add explanatory text to the 'Add your OpenPGP key' page in `atr/get/keys.py` (`add()` function) that explains the email address criteria. The text should clarify: (1) the key's User ID must contain an email address that ATR can link to the user's ASF identity, (2) an `@apache.org` email is the simplest option, (3) alternatively, any email address linked to the user's ASF account via `id.apache.org` will work, (4) this is a permanent record analogous to a commit. The guidance should appear between the page heading and the form, as a clear informational section.
   
   ### Suggested patches
   
   #### `atr/get/keys.py`
   Add explanatory guidance about email address selection criteria to the key addition page, as requested in the issue and elaborated by @sbp.
   
   ````diff
   --- a/atr/get/keys.py
   +++ b/atr/get/keys.py
   @@ -47,7 +47,26 @@
        page.p[htm.a(".atr-back-link", href=util.as_url(keys))["← Back to Manage keys"],]
        page.div(".my-4")[
            htm.h1(".mb-4")["Add your OpenPGP key"],
   -        htm.p["Add your public key to use for signing release artifacts."],
   +        htm.p["Add your public key to use for signing release artifacts. "
   +              "Your key's User ID (UID) must contain an email address that ATR can link to your ASF identity."],
   +    ]
   +
   +    page.div(".alert.alert-info.mb-4")[
   +        htm.p(".fw-semibold.mb-2")["Which email address should your key use?"],
   +        htm.ul(".mb-2")[
   +            htm.li[
   +                htm.strong["Recommended: "],
   +                "Use your ",
   +                htm.code["@apache.org"],
   +                " email address (e.g. ",
   +                htm.code["youruid@apache.org"],
   +                "). This is the simplest way for ATR to identify you.",
   +            ],
   +            htm.li[
   +                htm.strong["Alternative: "],
   +                "Use any email address that is linked to your ASF account via ",
   +                htm.a(href="https://id.apache.org")["id.apache.org"],
   +                ". ATR checks LDAP records to resolve linked addresses.",
   +            ],
   +        ],
   +        htm.p(".mb-0.text-muted")[
   +            "Adding a key is a permanent record, similar to a commit. "
   +            "Choose your email address carefully, as it will be publicly associated with your signed releases.",
   +        ],
        ]
        await form.render_block(
            page,
   ````
   
   ### Open questions
   - Should additional guidance also be added to a separate tutorial/documentation page outside the key addition form?
   - Should the explanation mention that if no matching email is found, ATR will still store the key but warn about the unresolved UID?
   - Are there any other pages (e.g., a key generation tutorial page not shown in this inventory) where this guidance should also appear?
   
   ### Files examined
   - `atr/shared/keys.py`
   - `atr/storage/writers/keys.py`
   - `atr/post/keys.py`
   - `atr/get/keys.py`
   
   ### Related issues
   This issue appears related to: #1198.
   
   _Both address clarity and documentation gaps in OpenPGP key management UI during user testing_
   
   ---
   *Draft from a triage agent. A human reviewer should validate before merging any change. The agent did not run tests or verify diffs apply.*


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@tooling.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tooling.apache.org
For additional commands, e-mail: dev-help@tooling.apache.org