Skip to content

Add configurable history username env injection for synced user keys#2

Merged
Msprg merged 9 commits intomasterfrom
feature/configurable-history-username-env
Feb 9, 2026
Merged

Add configurable history username env injection for synced user keys#2
Msprg merged 9 commits intomasterfrom
feature/configurable-history-username-env

Conversation

@Msprg
Copy link
Copy Markdown
Owner

@Msprg Msprg commented Feb 9, 2026

Summary by CodeRabbit

  • New Features

    • Per-server "History username env" setting (inherit/enable/disable) with optional format template; shown in server settings and read-only server view when key management is "keys".
    • Per-server history username env values are applied to generated authorized_keys entries during key preview and sync.
  • Chores

    • Database migration added to store new per-server settings.
  • Bug Fixes

    • Validation and user alerts for invalid format input.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds per-server "history username env" support: config example entries, DB migration to add mode/format columns, model resync trigger, UI/JS to edit/display options, server-side validation, and sync/key-generation changes to emit per-user per-server environment options into authorized_keys.

Changes

Cohort / File(s) Summary
Config & Migration
config/config.ini.example, migrations/010.php, model/migrationdirectory.php
Adds example config keys for history username env; migration adds history_username_env_mode (enum) and history_username_env_format columns; increments LAST_MIGRATION to 10.
Server Model
model/server.php
Includes history_username_env_mode and history_username_env_format in server update handling so changes trigger a resync.
Server UI & Views
templates/server.php, views/server.php, public_html/extra.js
Adds UI controls (inherit/enabled/disabled and optional format) displayed when key_management == 'keys'; client JS shows/hides block; server-side validation/assignment of mode and format on save.
Sync & Key Generation
scripts/sync.php
Threads $server through key assembly functions, adds per-server enablement/format resolution, escaping and authorized_keys option assembly, and propagates server context through group recursion so per-account per-server keyfiles include environment options.
Helpers
history_username_env_common.php
Adds history_username_env_format_is_valid() (validation of allowed characters, presence of {uid}, and disallowing problematic chars); other helper functions for default/normalization and server/global accessors introduced in sync logic.

Sequence Diagram

sequenceDiagram
    participant Admin as Administrator
    participant UI as Server Settings UI
    participant Model as Server Model
    participant DB as Database
    participant Sync as Sync Service
    participant Keys as Authorized_Keys

    Admin->>UI: Edit history_username_env mode & format, submit
    UI->>Model: Save server settings (mode, format)
    Model->>DB: UPDATE server.history_username_env_*
    DB-->>Model: OK
    Model->>Model: Mark server for resync
    Sync->>DB: Read server config for server
    DB-->>Sync: Return mode & format (or inherit)
    Sync->>Sync: Resolve effective env option (global → server → user)
    Sync->>Keys: Generate/write authorized_keys entries with env option prefix
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇
I nibble config lines with gentle cheer,
place {uid} where usernames appear,
per-server whispers, trimmed and neat,
I hop, I sync each tiny sheet,
keys hum softly — hop, repeat.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding configurable history username environment variable injection for synced user keys.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/configurable-history-username-env

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
templates/server.php (1)

402-427: Help text may confuse admins about when the fallback applies.

Line 425 says "If missing, sync falls back to BASH_HISTORY_USERNAME={uid}", but "missing" here could mean either (a) the format field is left blank on this server (inherits global format) or (b) the global format is also unconfigured (falls back to the hardcoded default). Consider clarifying, e.g.: "Leave empty to inherit global format. Ultimate default: BASH_HISTORY_USERNAME={uid}."

scripts/sync.php (1)

573-582: escape_authorized_keys_option_value does sanitization + validation + escaping — name understates scope.

The function strips control characters, validates, and escapes. Since the whitelist [A-Za-z0-9 ._@:+=-] already excludes \ and ", the str_replace on line 581 is effectively dead code (defense-in-depth). Consider renaming to sanitize_and_escape_authorized_keys_option_value or splitting, but this is a minor nit given the existing codebase style.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@scripts/sync.php`:
- Around line 510-516: The function get_global_history_username_env_enabled
currently defaults to true when
config['privacy']['history_username_env_default'] is absent, which can
unexpectedly inject environment="BASH_HISTORY_USERNAME=..." into
authorized_keys; change its default to false so it returns true only when
history_username_env_default is explicitly set to 1 (e.g., return
intval($config['privacy']['history_username_env_default']) === 1 when key
exists, otherwise return false), and update any upgrade notes or docs to mention
the behavioral change regarding authorized_keys injection and
PermitUserEnvironment.
- Around line 562-564: The escape_authorized_keys_option_value function must
also remove newlines and other control characters before escaping to prevent
breaking authorized_keys entries; update escape_authorized_keys_option_value to
first strip control characters (e.g. using a regex that removes [[:cntrl:]]
characters including "\r" and "\n") from $value, then perform the existing
backslash/quote escaping so the returned string contains no control characters
that could break or inject lines in authorized_keys.

In `@views/server.php`:
- Around line 124-136: Validate and sanitize history_username_env_format on
input before storing: after trimming and checking for empty, ensure the string
contains the required "{uid}" and matches a strict whitelist regex (e.g. allow
only letters, digits, spaces and a small safe set of symbols such as - _ . @ : +
and the braces for {uid}) and explicitly reject or null-out any value containing
newline, comma, equals, quotes, backslash or other disallowed chars; enforce the
same validation in normalize_history_username_env_format so storage and later
use (and escape_authorized_keys_option_value in scripts/sync.php) cannot be
bypassed. Reference variables/functions: $history_username_env_format,
$server->history_username_env_format, normalize_history_username_env_format(),
and escape_authorized_keys_option_value().
🧹 Nitpick comments (2)
templates/server.php (1)

390-393: Inconsistent indentation on the no-pty checkbox.

The no-pty checkbox div (lines 390-392) has an extra indentation level compared to its sibling checkbox divs (lines 384-389). This appears to be an unintended whitespace change.

Proposed fix
-						<div class="checkbox">
-							<label><input type="checkbox" name="access_option[no-pty][enabled]"<?php if(isset($options['no-pty'])) out(' checked'); ?>> Disable terminal (<code>no-pty</code>)</label>
-						</div>
+					<div class="checkbox">
+						<label><input type="checkbox" name="access_option[no-pty][enabled]"<?php if(isset($options['no-pty'])) out(' checked'); ?>> Disable terminal (<code>no-pty</code>)</label>
+					</div>
scripts/sync.php (1)

574-580: Consider validating that the expanded format contains a = sign.

OpenSSH's environment option expects NAME=value syntax. If an admin configures a format like {uid} (without an =), the resulting environment="jsmith" is technically malformed. normalize_history_username_env_format checks for {uid} presence but not structural validity. A quick check could prevent subtle misconfigurations.

Comment thread scripts/sync.php
Comment thread scripts/sync.php
@Msprg Msprg force-pushed the feature/configurable-history-username-env branch from 4069cfb to 3defb4b Compare February 9, 2026 16:20
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _____________________________________________\n> < Because, no one wants to be a human linter. >\n>  ---------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>You can customize the high-level summary generated by CodeRabbit.</summary>\n> \n> Configure the `reviews.high_level_summary_instructions` setting to provide custom instructions for generating the high-level summary.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis PR introduces support for managing environment variables in SSH authorized_keys entries, with per-server configuration options that can inherit from or override global defaults. The feature includes database schema extensions, server model updates, key generation logic modifications, and UI controls for configuring history username environment behavior.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Database Schema** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|Added two new configuration options for history username environment defaults and format. Database migration extends server table with `history_username_env_mode` (enum) and `history_username_env_format` (varchar). Migration counter incremented to 10.|\n|**Server Model & Data Layer** <br> `model/server.php`|Extended resync trigger logic to include two new fields (`history_username_env_mode`, `history_username_env_format`) that flag servers requiring key resynchronization when modified.|\n|**Key Generation & Sync Logic** <br> `scripts/sync.php`|Significantly expanded key generation pipeline with 15+ new helper functions managing history environment option formatting, per-server overrides, and global settings. Modified `append_user_keys`, `get_keys`, and `get_group_keys` signatures to accept server context and apply per-entity history environment prefixes to authorized_keys entries.|\n|**Server Settings UI & Views** <br> `public_html/extra.js`, `templates/server.php`, `views/server.php`|Added visibility toggle for history environment settings in the server form tied to key-based authorization. Extended server settings UI with radio options (inherit/enabled/disabled) and optional format override field. Added POST form processing to validate and store the new configuration fields.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Script\n    participant Keys as Authorized Keys\n\n    Admin->>UI: Configure history_username_env settings\n    UI->>Model: Submit form (mode, format)\n    Model->>Model: Validate & normalize settings\n    Model->>DB: Update server record\n    DB->>DB: Store history_username_env_mode & format\n    DB-->>Model: Confirmation\n    Model->>Model: Mark resync needed\n    Sync->>DB: Read server settings\n    DB-->>Sync: Retrieve history_username_env config\n    Sync->>Sync: Determine effective format (inherit/override)\n    Sync->>Sync: Generate keys with env options\n    Sync->>Keys: Write authorized_keys with BASH_HISTORY_USERNAME prefix\n    Keys-->>Admin: Keys updated with history tracking\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly Related PRs\n\n- **Msprg/ssh-key-authority#1** — Directly modifies overlapping key-generation functions in `scripts/sync.php` (append_user_keys, get_keys, get_group_keys) with related signature changes for server context propagation.\n\n## Poem\n\n> 🐰 *With whiskers twitching at the task so grand,*  \n> *SSH keys now remember where they've been,*  \n> *Per-server history, per-admin's command,*  \n> *Environment variables dance in between—*  \n> *A rabbit hops through authorized_keys, serene!* 🔑\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                              |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                              |\n|    Title check    | ✅ Passed | The title accurately and specifically describes the main change: adding configurable history username environment variable injection for synced user keys. It directly relates to the primary changeset. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:21:21 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082E:3D75D9:106BE18:467821D:698A0980","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4933","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"67","x-xss-protection":"0"},"data":""}}

3 similar comments
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _____________________________________________\n> < Because, no one wants to be a human linter. >\n>  ---------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>You can customize the high-level summary generated by CodeRabbit.</summary>\n> \n> Configure the `reviews.high_level_summary_instructions` setting to provide custom instructions for generating the high-level summary.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis PR introduces support for managing environment variables in SSH authorized_keys entries, with per-server configuration options that can inherit from or override global defaults. The feature includes database schema extensions, server model updates, key generation logic modifications, and UI controls for configuring history username environment behavior.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Database Schema** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|Added two new configuration options for history username environment defaults and format. Database migration extends server table with `history_username_env_mode` (enum) and `history_username_env_format` (varchar). Migration counter incremented to 10.|\n|**Server Model & Data Layer** <br> `model/server.php`|Extended resync trigger logic to include two new fields (`history_username_env_mode`, `history_username_env_format`) that flag servers requiring key resynchronization when modified.|\n|**Key Generation & Sync Logic** <br> `scripts/sync.php`|Significantly expanded key generation pipeline with 15+ new helper functions managing history environment option formatting, per-server overrides, and global settings. Modified `append_user_keys`, `get_keys`, and `get_group_keys` signatures to accept server context and apply per-entity history environment prefixes to authorized_keys entries.|\n|**Server Settings UI & Views** <br> `public_html/extra.js`, `templates/server.php`, `views/server.php`|Added visibility toggle for history environment settings in the server form tied to key-based authorization. Extended server settings UI with radio options (inherit/enabled/disabled) and optional format override field. Added POST form processing to validate and store the new configuration fields.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Script\n    participant Keys as Authorized Keys\n\n    Admin->>UI: Configure history_username_env settings\n    UI->>Model: Submit form (mode, format)\n    Model->>Model: Validate & normalize settings\n    Model->>DB: Update server record\n    DB->>DB: Store history_username_env_mode & format\n    DB-->>Model: Confirmation\n    Model->>Model: Mark resync needed\n    Sync->>DB: Read server settings\n    DB-->>Sync: Retrieve history_username_env config\n    Sync->>Sync: Determine effective format (inherit/override)\n    Sync->>Sync: Generate keys with env options\n    Sync->>Keys: Write authorized_keys with BASH_HISTORY_USERNAME prefix\n    Keys-->>Admin: Keys updated with history tracking\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly Related PRs\n\n- **Msprg/ssh-key-authority#1** — Directly modifies overlapping key-generation functions in `scripts/sync.php` (append_user_keys, get_keys, get_group_keys) with related signature changes for server context propagation.\n\n## Poem\n\n> 🐰 *With whiskers twitching at the task so grand,*  \n> *SSH keys now remember where they've been,*  \n> *Per-server history, per-admin's command,*  \n> *Environment variables dance in between—*  \n> *A rabbit hops through authorized_keys, serene!* 🔑\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                              |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                              |\n|    Title check    | ✅ Passed | The title accurately and specifically describes the main change: adding configurable history username environment variable injection for synced user keys. It directly relates to the primary changeset. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:21:21 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082E:3D75D9:106BE18:467821D:698A0980","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4933","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"67","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _____________________________________________\n> < Because, no one wants to be a human linter. >\n>  ---------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>You can customize the high-level summary generated by CodeRabbit.</summary>\n> \n> Configure the `reviews.high_level_summary_instructions` setting to provide custom instructions for generating the high-level summary.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis PR introduces support for managing environment variables in SSH authorized_keys entries, with per-server configuration options that can inherit from or override global defaults. The feature includes database schema extensions, server model updates, key generation logic modifications, and UI controls for configuring history username environment behavior.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Database Schema** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|Added two new configuration options for history username environment defaults and format. Database migration extends server table with `history_username_env_mode` (enum) and `history_username_env_format` (varchar). Migration counter incremented to 10.|\n|**Server Model & Data Layer** <br> `model/server.php`|Extended resync trigger logic to include two new fields (`history_username_env_mode`, `history_username_env_format`) that flag servers requiring key resynchronization when modified.|\n|**Key Generation & Sync Logic** <br> `scripts/sync.php`|Significantly expanded key generation pipeline with 15+ new helper functions managing history environment option formatting, per-server overrides, and global settings. Modified `append_user_keys`, `get_keys`, and `get_group_keys` signatures to accept server context and apply per-entity history environment prefixes to authorized_keys entries.|\n|**Server Settings UI & Views** <br> `public_html/extra.js`, `templates/server.php`, `views/server.php`|Added visibility toggle for history environment settings in the server form tied to key-based authorization. Extended server settings UI with radio options (inherit/enabled/disabled) and optional format override field. Added POST form processing to validate and store the new configuration fields.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Script\n    participant Keys as Authorized Keys\n\n    Admin->>UI: Configure history_username_env settings\n    UI->>Model: Submit form (mode, format)\n    Model->>Model: Validate & normalize settings\n    Model->>DB: Update server record\n    DB->>DB: Store history_username_env_mode & format\n    DB-->>Model: Confirmation\n    Model->>Model: Mark resync needed\n    Sync->>DB: Read server settings\n    DB-->>Sync: Retrieve history_username_env config\n    Sync->>Sync: Determine effective format (inherit/override)\n    Sync->>Sync: Generate keys with env options\n    Sync->>Keys: Write authorized_keys with BASH_HISTORY_USERNAME prefix\n    Keys-->>Admin: Keys updated with history tracking\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly Related PRs\n\n- **Msprg/ssh-key-authority#1** — Directly modifies overlapping key-generation functions in `scripts/sync.php` (append_user_keys, get_keys, get_group_keys) with related signature changes for server context propagation.\n\n## Poem\n\n> 🐰 *With whiskers twitching at the task so grand,*  \n> *SSH keys now remember where they've been,*  \n> *Per-server history, per-admin's command,*  \n> *Environment variables dance in between—*  \n> *A rabbit hops through authorized_keys, serene!* 🔑\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                              |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                              |\n|    Title check    | ✅ Passed | The title accurately and specifically describes the main change: adding configurable history username environment variable injection for synced user keys. It directly relates to the primary changeset. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:21:21 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082E:3D75D9:106BE18:467821D:698A0980","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4933","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"67","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> \n> \n> ```ascii\n>  _____________________________________________\n> < Because, no one wants to be a human linter. >\n>  ---------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n> \n> <sub>✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.</sub>\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n<!-- usage_tips_start -->\n\n> [!TIP]\n> <details>\n> <summary>You can customize the high-level summary generated by CodeRabbit.</summary>\n> \n> Configure the `reviews.high_level_summary_instructions` setting to provide custom instructions for generating the high-level summary.\n> \n> </details>\n\n<!-- usage_tips_end -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis PR introduces support for managing environment variables in SSH authorized_keys entries, with per-server configuration options that can inherit from or override global defaults. The feature includes database schema extensions, server model updates, key generation logic modifications, and UI controls for configuring history username environment behavior.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Database Schema** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|Added two new configuration options for history username environment defaults and format. Database migration extends server table with `history_username_env_mode` (enum) and `history_username_env_format` (varchar). Migration counter incremented to 10.|\n|**Server Model & Data Layer** <br> `model/server.php`|Extended resync trigger logic to include two new fields (`history_username_env_mode`, `history_username_env_format`) that flag servers requiring key resynchronization when modified.|\n|**Key Generation & Sync Logic** <br> `scripts/sync.php`|Significantly expanded key generation pipeline with 15+ new helper functions managing history environment option formatting, per-server overrides, and global settings. Modified `append_user_keys`, `get_keys`, and `get_group_keys` signatures to accept server context and apply per-entity history environment prefixes to authorized_keys entries.|\n|**Server Settings UI & Views** <br> `public_html/extra.js`, `templates/server.php`, `views/server.php`|Added visibility toggle for history environment settings in the server form tied to key-based authorization. Extended server settings UI with radio options (inherit/enabled/disabled) and optional format override field. Added POST form processing to validate and store the new configuration fields.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Script\n    participant Keys as Authorized Keys\n\n    Admin->>UI: Configure history_username_env settings\n    UI->>Model: Submit form (mode, format)\n    Model->>Model: Validate & normalize settings\n    Model->>DB: Update server record\n    DB->>DB: Store history_username_env_mode & format\n    DB-->>Model: Confirmation\n    Model->>Model: Mark resync needed\n    Sync->>DB: Read server settings\n    DB-->>Sync: Retrieve history_username_env config\n    Sync->>Sync: Determine effective format (inherit/override)\n    Sync->>Sync: Generate keys with env options\n    Sync->>Keys: Write authorized_keys with BASH_HISTORY_USERNAME prefix\n    Keys-->>Admin: Keys updated with history tracking\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly Related PRs\n\n- **Msprg/ssh-key-authority#1** — Directly modifies overlapping key-generation functions in `scripts/sync.php` (append_user_keys, get_keys, get_group_keys) with related signature changes for server context propagation.\n\n## Poem\n\n> 🐰 *With whiskers twitching at the task so grand,*  \n> *SSH keys now remember where they've been,*  \n> *Per-server history, per-admin's command,*  \n> *Environment variables dance in between—*  \n> *A rabbit hops through authorized_keys, serene!* 🔑\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                              |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                              |\n|    Title check    | ✅ Passed | The title accurately and specifically describes the main change: adding configurable history username environment variable injection for synced user keys. It directly relates to the primary changeset. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:21:21 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082E:3D75D9:106BE18:467821D:698A0980","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4933","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"67","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-server \"history username env\" settings with global defaults, DB migration to store mode/format, server model updates to trigger resync, UI controls and JS visibility, and extensive sync/key-generation changes to apply formatted environment options to authorized_keys entries.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Migration** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|New global config options for history username env default/format; migration adds `history_username_env_mode` (enum) and `history_username_env_format` (varchar) to `server` table; migration counter bumped to 10.|\n|**Server Model** <br> `model/server.php`|Includes `history_username_env_mode` and `history_username_env_format` in update/resync trigger fields.|\n|**Server UI & Views** <br> `templates/server.php`, `views/server.php`, `public_html/extra.js`|Adds form controls (inherit/enabled/disabled + optional format) and display logic; processes and validates POSTed mode/format; JS toggles visibility when key management is `keys`.|\n|**Sync & Key Generation** <br> `scripts/sync.php`|Introduces many helper functions and server-aware logic to normalize/resolve global and per-server history env settings, escape/append authorized_keys options, and propagate `$server` through `get_keys`, `get_group_keys`, `append_user_keys`, and related flows so per-user history env entries are prepended to keys.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Service\n    participant Keys as Authorized_Keys\n\n    Admin->>UI: Edit server (mode, format) and submit\n    UI->>Model: Save mode & format\n    Model->>DB: UPDATE server.history_username_env_*\n    DB-->>Model: OK\n    Model->>Model: Mark server for resync\n    Sync->>DB: Read server config during sync\n    DB-->>Sync: Return mode & format (or inherit)\n    Sync->>Sync: Compute effective env option (global/server/normalize)\n    Sync->>Keys: Generate/write authorized_keys entries with env option prefix\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Poem\n\n> 🐰  \n> *I twitch my nose at lines of code,*  \n> *A tiny env to trace the road,*  \n> *Per-server whispers, formatted neat,*  \n> *Authorized keys with history's beat,*  \n> *A rabbit hums — the sync's complete.*\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                                   |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                   |\n|    Title check    | ✅ Passed | The title clearly and specifically describes the main change: adding configurable history username environment variable injection for synced user keys, which is the primary focus across all modified files. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>scripts/sync.php (1)</summary><blockquote>\n\n`526-536`: **Broad `Exception` catch used for property access.**\n\nCatching the base `Exception` class to handle a missing property silently masks unrelated errors (e.g., database connectivity issues). Consider catching only the specific exception type that `$server->history_username_env_mode` would throw when the property is absent, or use `isset`/`property_exists` instead.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:25:14 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082A:2EFC7B:EBA233:3F8338B:698A0A68","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4916","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"84","x-xss-protection":"0"},"data":""}}

3 similar comments
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-server \"history username env\" settings with global defaults, DB migration to store mode/format, server model updates to trigger resync, UI controls and JS visibility, and extensive sync/key-generation changes to apply formatted environment options to authorized_keys entries.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Migration** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|New global config options for history username env default/format; migration adds `history_username_env_mode` (enum) and `history_username_env_format` (varchar) to `server` table; migration counter bumped to 10.|\n|**Server Model** <br> `model/server.php`|Includes `history_username_env_mode` and `history_username_env_format` in update/resync trigger fields.|\n|**Server UI & Views** <br> `templates/server.php`, `views/server.php`, `public_html/extra.js`|Adds form controls (inherit/enabled/disabled + optional format) and display logic; processes and validates POSTed mode/format; JS toggles visibility when key management is `keys`.|\n|**Sync & Key Generation** <br> `scripts/sync.php`|Introduces many helper functions and server-aware logic to normalize/resolve global and per-server history env settings, escape/append authorized_keys options, and propagate `$server` through `get_keys`, `get_group_keys`, `append_user_keys`, and related flows so per-user history env entries are prepended to keys.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Service\n    participant Keys as Authorized_Keys\n\n    Admin->>UI: Edit server (mode, format) and submit\n    UI->>Model: Save mode & format\n    Model->>DB: UPDATE server.history_username_env_*\n    DB-->>Model: OK\n    Model->>Model: Mark server for resync\n    Sync->>DB: Read server config during sync\n    DB-->>Sync: Return mode & format (or inherit)\n    Sync->>Sync: Compute effective env option (global/server/normalize)\n    Sync->>Keys: Generate/write authorized_keys entries with env option prefix\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Poem\n\n> 🐰  \n> *I twitch my nose at lines of code,*  \n> *A tiny env to trace the road,*  \n> *Per-server whispers, formatted neat,*  \n> *Authorized keys with history's beat,*  \n> *A rabbit hums — the sync's complete.*\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                                   |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                   |\n|    Title check    | ✅ Passed | The title clearly and specifically describes the main change: adding configurable history username environment variable injection for synced user keys, which is the primary focus across all modified files. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>scripts/sync.php (1)</summary><blockquote>\n\n`526-536`: **Broad `Exception` catch used for property access.**\n\nCatching the base `Exception` class to handle a missing property silently masks unrelated errors (e.g., database connectivity issues). Consider catching only the specific exception type that `$server->history_username_env_mode` would throw when the property is absent, or use `isset`/`property_exists` instead.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:25:14 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082A:2EFC7B:EBA233:3F8338B:698A0A68","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4916","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"84","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-server \"history username env\" settings with global defaults, DB migration to store mode/format, server model updates to trigger resync, UI controls and JS visibility, and extensive sync/key-generation changes to apply formatted environment options to authorized_keys entries.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Migration** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|New global config options for history username env default/format; migration adds `history_username_env_mode` (enum) and `history_username_env_format` (varchar) to `server` table; migration counter bumped to 10.|\n|**Server Model** <br> `model/server.php`|Includes `history_username_env_mode` and `history_username_env_format` in update/resync trigger fields.|\n|**Server UI & Views** <br> `templates/server.php`, `views/server.php`, `public_html/extra.js`|Adds form controls (inherit/enabled/disabled + optional format) and display logic; processes and validates POSTed mode/format; JS toggles visibility when key management is `keys`.|\n|**Sync & Key Generation** <br> `scripts/sync.php`|Introduces many helper functions and server-aware logic to normalize/resolve global and per-server history env settings, escape/append authorized_keys options, and propagate `$server` through `get_keys`, `get_group_keys`, `append_user_keys`, and related flows so per-user history env entries are prepended to keys.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Service\n    participant Keys as Authorized_Keys\n\n    Admin->>UI: Edit server (mode, format) and submit\n    UI->>Model: Save mode & format\n    Model->>DB: UPDATE server.history_username_env_*\n    DB-->>Model: OK\n    Model->>Model: Mark server for resync\n    Sync->>DB: Read server config during sync\n    DB-->>Sync: Return mode & format (or inherit)\n    Sync->>Sync: Compute effective env option (global/server/normalize)\n    Sync->>Keys: Generate/write authorized_keys entries with env option prefix\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Poem\n\n> 🐰  \n> *I twitch my nose at lines of code,*  \n> *A tiny env to trace the road,*  \n> *Per-server whispers, formatted neat,*  \n> *Authorized keys with history's beat,*  \n> *A rabbit hums — the sync's complete.*\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                                   |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                   |\n|    Title check    | ✅ Passed | The title clearly and specifically describes the main change: adding configurable history username environment variable injection for synced user keys, which is the primary focus across all modified files. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>scripts/sync.php (1)</summary><blockquote>\n\n`526-536`: **Broad `Exception` catch used for property access.**\n\nCatching the base `Exception` class to handle a missing property silently masks unrelated errors (e.g., database connectivity issues). Consider catching only the specific exception type that `$server->history_username_env_mode` would throw when the property is absent, or use `isset`/`property_exists` instead.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:25:14 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082A:2EFC7B:EBA233:3F8338B:698A0A68","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4916","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"84","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-server \"history username env\" settings with global defaults, DB migration to store mode/format, server model updates to trigger resync, UI controls and JS visibility, and extensive sync/key-generation changes to apply formatted environment options to authorized_keys entries.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Configuration & Migration** <br> `config/config.ini.example`, `migrations/010.php`, `model/migrationdirectory.php`|New global config options for history username env default/format; migration adds `history_username_env_mode` (enum) and `history_username_env_format` (varchar) to `server` table; migration counter bumped to 10.|\n|**Server Model** <br> `model/server.php`|Includes `history_username_env_mode` and `history_username_env_format` in update/resync trigger fields.|\n|**Server UI & Views** <br> `templates/server.php`, `views/server.php`, `public_html/extra.js`|Adds form controls (inherit/enabled/disabled + optional format) and display logic; processes and validates POSTed mode/format; JS toggles visibility when key management is `keys`.|\n|**Sync & Key Generation** <br> `scripts/sync.php`|Introduces many helper functions and server-aware logic to normalize/resolve global and per-server history env settings, escape/append authorized_keys options, and propagate `$server` through `get_keys`, `get_group_keys`, `append_user_keys`, and related flows so per-user history env entries are prepended to keys.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant Admin as Administrator\n    participant UI as Server Settings UI\n    participant Model as Server Model\n    participant DB as Database\n    participant Sync as Sync Service\n    participant Keys as Authorized_Keys\n\n    Admin->>UI: Edit server (mode, format) and submit\n    UI->>Model: Save mode & format\n    Model->>DB: UPDATE server.history_username_env_*\n    DB-->>Model: OK\n    Model->>Model: Mark server for resync\n    Sync->>DB: Read server config during sync\n    DB-->>Sync: Return mode & format (or inherit)\n    Sync->>Sync: Compute effective env option (global/server/normalize)\n    Sync->>Keys: Generate/write authorized_keys entries with env option prefix\n```\n\n## Estimated Code Review Effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Poem\n\n> 🐰  \n> *I twitch my nose at lines of code,*  \n> *A tiny env to trace the road,*  \n> *Per-server whispers, formatted neat,*  \n> *Authorized keys with history's beat,*  \n> *A rabbit hums — the sync's complete.*\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                                   |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                   |\n|    Title check    | ✅ Passed | The title clearly and specifically describes the main change: adding configurable history username environment variable injection for synced user keys, which is the primary focus across all modified files. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature/configurable-history-username-env`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>scripts/sync.php (1)</summary><blockquote>\n\n`526-536`: **Broad `Exception` catch used for property access.**\n\nCatching the base `Exception` class to handle a missing property silently masks unrelated errors (e.g., database connectivity issues). Consider catching only the specific exception type that `$server->history_username_env_mode` would throw when the property is absent, or use `isset`/`property_exists` instead.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Msprg/ssh-key-authority&utm_content=2)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/Msprg/ssh-key-authority/issues/comments/3872551289","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:25:14 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"082A:2EFC7B:EBA233:3F8338B:698A0A68","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4916","x-ratelimit-reset":"1770655810","x-ratelimit-resource":"core","x-ratelimit-used":"84","x-xss-protection":"0"},"data":""}}

Msprg and others added 4 commits February 9, 2026 16:40
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Default get_global_history_username_env_enabled to false instead of true to avoid breaking exisitng deployments

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…r.php

- Added validation functions for history username environment format and value.
- Updated normalization and user history environment option functions to utilize new validation.
- Improved handling of history username environment format in server settings.

This ensures that invalid formats are properly handled, enhancing overall robustness.
…ction in sync.php

- Added a regex to remove control characters from the input value.
- Ensured that null values are converted to empty strings before validation.

This improves the robustness of the authorized keys option handling.
@Msprg Msprg force-pushed the feature/configurable-history-username-env branch from d957102 to 9c8a8d5 Compare February 9, 2026 16:46
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@scripts/sync.php`:
- Around line 502-527: The validation currently rejects '=' causing the default
format and values to fail; update history_username_env_format_is_valid and
history_username_env_value_is_valid to allow '=' by removing it from the
blacklist patterns (/[\r\n,=\'"\\\\]/ and /[\r\n,=\'"\\\\{}]/) and include '='
in the whitelist character classes (/^[A-Za-z0-9 ._@:+{}-]+$/ and /^[A-Za-z0-9
._@:+-]+$/) so that formats like "BASH_HISTORY_USERNAME={uid}" and values like
"BASH_HISTORY_USERNAME=john" pass validation (this will restore behavior used by
get_user_history_username_env_option()).

In `@views/server.php`:
- Around line 41-56: The function history_username_env_format_is_valid(...) is
duplicated; extract this function into a single shared include (e.g.,
sync-common.php or utilities include) and remove the duplicate definitions, then
require_once that shared file from both places that currently define it (the
server.php and scripts/sync.php locations) so both use the same implementation;
keep the function name unchanged, update the includes to require_once the new
file, and run tests to ensure no symbol collisions or missing includes.
- Around line 141-159: The user-facing alert says equals signs are allowed but
history_username_env_format_is_valid currently rejects '='; update the
validation function history_username_env_format_is_valid to accept '=' (and
ensure it still accepts alphanumerics, underscores, hyphens, and curly braces),
or alternatively change the alert text to list exactly what the validator
allows; make the code paths around $history_username_env_format (where the alert
is created and $server->history_username_env_format is set) consistent with the
validator so the message matches the actual allowed characters.

Comment thread scripts/sync.php Outdated
Comment thread views/server.php Outdated
Comment thread views/server.php
Comment on lines +141 to +159
$history_username_env_mode = isset($_POST['history_username_env_mode']) ? $_POST['history_username_env_mode'] : 'inherit';
if($history_username_env_mode !== 'inherit' && $history_username_env_mode !== 'enabled' && $history_username_env_mode !== 'disabled') {
$history_username_env_mode = 'inherit';
}
$history_username_env_format = null;
if(isset($_POST['history_username_env_format'])) {
$history_username_env_format = trim($_POST['history_username_env_format']);
if($history_username_env_format === '') {
$history_username_env_format = null;
} elseif(!history_username_env_format_is_valid($history_username_env_format)) {
$alert = new UserAlert;
$alert->content = "Invalid history username env format. Only alphanumeric characters, underscores, hyphens, equals signs, and curly braces are allowed.";
$alert->class = 'danger';
$active_user->add_alert($alert);
$history_username_env_format = null;
}
}
$server->history_username_env_mode = $history_username_env_mode;
$server->history_username_env_format = $history_username_env_format;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Mode validation and format handling look correct, pending the = fix.

The mode normalization (Lines 141-144) properly constrains to known values. Format validation (Lines 146-156) provides a clear user alert on invalid input. However, note that the error message at Line 152 says "equals signs" are allowed, but the validation actually rejects them — this will need to be corrected alongside the = fix in the validation function.

🤖 Prompt for AI Agents
In `@views/server.php` around lines 141 - 159, The user-facing alert says equals
signs are allowed but history_username_env_format_is_valid currently rejects
'='; update the validation function history_username_env_format_is_valid to
accept '=' (and ensure it still accepts alphanumerics, underscores, hyphens, and
curly braces), or alternatively change the alert text to list exactly what the
validator allows; make the code paths around $history_username_env_format (where
the alert is created and $server->history_username_env_format is set) consistent
with the validator so the message matches the actual allowed characters.

…sync.php

- Updated regex to exclude additional characters in format and value validation functions.
- Enhanced the allowed character set for the format to include '=' and '-' for better flexibility.

This improves the accuracy of validation for history username environment inputs.
@Msprg
Copy link
Copy Markdown
Owner Author

Msprg commented Feb 9, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

✅ Actions performed

Full review triggered.

@Msprg
Copy link
Copy Markdown
Owner Author

Msprg commented Feb 9, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

✅ Actions performed

Full review triggered.

Msprg added 3 commits February 9, 2026 18:04
- Moved the history username environment format validation function from sync.php and server.php to a new common file, history_username_env_common.php.
- Updated sync.php and server.php to include the new common file for validation, improving code organization and reusability.

This change centralizes the validation logic, enhancing maintainability and consistency across the application.
…on in server.php

- Revised the alert content to specify the allowed characters and format requirements for the history username environment.
- This change enhances clarity for users encountering validation errors, ensuring they understand the expected input format.
…file

- Added a check to ensure the format includes an '=' character in the history_username_env_format_is_valid function.
- Updated the error message in server.php to reflect the new validation requirement, clarifying that both '=' and '{uid}' must be present.

This improves the accuracy of format validation and user feedback for history username environments.
@Msprg
Copy link
Copy Markdown
Owner Author

Msprg commented Feb 9, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

✅ Actions performed

Full review triggered.

@Msprg Msprg merged commit 7cbdcde into master Feb 9, 2026
4 checks passed
@Msprg Msprg deleted the feature/configurable-history-username-env branch February 9, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant