Skip to content

feat: Init Agent Intergation #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 15, 2025
Merged

feat: Init Agent Intergation #3

merged 19 commits into from
Apr 15, 2025

Conversation

zacharyblasczyk
Copy link
Member

@zacharyblasczyk zacharyblasczyk commented Apr 12, 2025

Summary by CodeRabbit

  • New Features

    • Introduced Ctrlplane Job Agent polling and job reconciliation in Jenkins.
    • Added global configuration UI for Ctrlplane integration with validation and persistence.
    • Provided a new pipeline step to fetch Ctrlplane job details within Jenkins pipelines.
    • Implemented event listener to synchronize Jenkins job completion status back to Ctrlplane.
  • Localization

    • Added extensive multilingual support for configuration UI and help texts (English, German, Spanish, French, Italian, Portuguese, Swedish, Turkish, Chinese).
  • Documentation

    • Updated README with plugin description and official documentation links.
    • Added CONTRIBUTING guide to assist contributors.
    • Enhanced configuration help texts across supported languages.
  • Bug Fixes

    • Removed deprecated sample builder and all associated configuration, localization, and tests.
  • Tests

    • Added thorough unit and integration tests covering configuration, job polling, job processing, pipeline step functionality, and configuration change handling.
  • Chores

    • Improved .gitignore to exclude IDE and work directories.
    • Updated repository ownership to individual maintainers.
    • Upgraded plugin metadata and dependencies for better compatibility and maintainability.

Copy link
Contributor

coderabbitai bot commented Apr 12, 2025

Walkthrough

This update introduces a comprehensive integration between Jenkins and Ctrlplane, establishing a job agent system that polls Ctrlplane for jobs and synchronizes job statuses. Major changes include the addition of core Java classes for global configuration, job polling, job completion listening, and a pipeline step for fetching job details from Ctrlplane. The plugin's configuration UI is implemented with localization support in multiple languages. The build system and dependencies are updated, and extensive help and documentation files are added. Sample and legacy files related to the previous "HelloWorldBuilder" are removed, and new tests validate the Ctrlplane integration. The README and contributing guidelines are updated to reflect the new plugin focus.

Changes

File(s) / Path(s) Change Summary
.gitignore Added .idea/ and work/ to ignore JetBrains IDE and work directories.
.github/CODEOWNERS Changed code ownership from a team to two individual users.
.vscode/settings.json Added Java build configuration auto-update setting.
CONTRIBUTING.md New file with detailed contribution instructions, including code style and formatting guidelines.
Jenkinsfile Minor formatting and comment removal in plugin build configuration.
README.md Updated to describe the Ctrlplane Jenkins integration, revise links, and remove placeholders.
example.Jenkinsfile Simplified pipeline: removed API_URL parameter, updated job fetch logic to use ctrlplaneGetJob, and improved output formatting.
pom.xml Updated parent and BOM versions, restructured dependencies, added developers, changed project and repo names, set Jenkins baseline, and updated dependency scopes and artifact IDs.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java New class: Implements global configuration for the Ctrlplane agent, with validation and persistence.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java New class: Implements background polling of Ctrlplane for jobs, triggers Jenkins jobs, and reconciles job statuses.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java New class: Listens for Jenkins job completion and updates Ctrlplane job status accordingly.
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java New class: Handles agent registration, job polling, and job status updates via Ctrlplane API.
src/main/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStep.java New class: Jenkins pipeline step to fetch job details from Ctrlplane API, with validation and error handling.
src/main/resources/index.jelly Replaced static "TODO" text with dynamic plugin description and configuration placeholders.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly New Jelly file: Defines UI for global configuration of Ctrlplane agent settings.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey.html New help file: Explains API key purpose and retrieval for Ctrlplane configuration.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl.html New help file: Describes API URL configuration and default value.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.properties New: English localization for configuration UI fields and descriptions.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_de.properties New: German localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_es.properties New: Spanish localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_fr.properties New: French localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_it.properties New: Italian localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_pt_BR.properties New: Brazilian Portuguese localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_sv.properties New: Swedish localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_tr.properties New: Turkish localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_zh_CN.properties New: Simplified Chinese localization for configuration UI.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_*.html New: Help files for API key field in German, Spanish, French, Italian, Portuguese (BR), Swedish, Turkish, and Chinese.
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_*.html New: Help files for API URL field in German, Spanish, French, Italian, Portuguese (BR), Swedish, Turkish, and Chinese.
src/main/resources/io/jenkins/plugins/ctrlplane/Messages.properties New: Plugin description and configuration instructions in English.
src/main/resources/io/jenkins/plugins/ctrlplane/Messages_*.properties New: Plugin description and configuration instructions in German, Spanish, French, Italian, Portuguese (BR), Swedish, Turkish, and Chinese.
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java New test: Validates configuration UI, persistence, and default values for global configuration.
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java New test: Unit tests for job name extraction and job triggering logic in job poller.
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java New test: Mock-based tests for job poller logic, job info extraction, and job status updates.
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneConfigChangeTest.java New test: Validates job agent re-initialization logic on configuration change.
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobProcessingTest.java New test: Tests job info extraction, job processing stats, and job completion handling in job poller.
src/test/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStepTest.java New test: Validates pipeline step input validation, execution, logging, configuration access, and descriptor.
src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java
src/test/java/io/jenkins/plugins/sample/HelloWorldBuilderTest.java
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_de.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_es.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_it.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_pt_BR.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_sv.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_tr.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_zh_CN.properties
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_de.html
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html
src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_de.html
src/main/resources/io/jenkins/plugins/sample/Messages.properties
src/main/resources/io/jenkins/plugins/sample/Messages_de.properties
Removed all files and tests related to the previous HelloWorldBuilder sample, including code, configuration, localization, and help files.
src/utils/CtrlplaneClient.groovy Removed legacy Groovy client for fetching Ctrlplane job data.

Sequence Diagram(s)

sequenceDiagram
    participant Jenkins as Jenkins Core
    participant User as Jenkins User/Admin
    participant CtrlplanePlugin as Ctrlplane Plugin
    participant CtrlplaneAPI as Ctrlplane API

    User->>Jenkins: Configure Ctrlplane settings (UI)
    Jenkins->>CtrlplanePlugin: Save configuration

    loop Periodic Polling
        CtrlplanePlugin->>CtrlplaneAPI: Poll for pending jobs
        CtrlplaneAPI-->>CtrlplanePlugin: Return job list
        alt Jobs available
            CtrlplanePlugin->>Jenkins: Trigger job with parameters
            Jenkins-->>CtrlplanePlugin: Job queued/running
            note over Jenkins,CtrlplanePlugin: Track job status
        end
    end

    Jenkins->>CtrlplanePlugin: Job completes (RunListener)
    CtrlplanePlugin->>CtrlplaneAPI: Update job status (success/failure/cancelled)
Loading
sequenceDiagram
    participant Pipeline as Jenkins Pipeline
    participant CtrlplanePlugin as Ctrlplane Plugin
    participant CtrlplaneAPI as Ctrlplane API

    Pipeline->>CtrlplanePlugin: ctrlplaneGetJob(JOB_ID)
    CtrlplanePlugin->>CtrlplaneAPI: Fetch job details (GET /jobs/{id})
    CtrlplaneAPI-->>CtrlplanePlugin: Return job details
    CtrlplanePlugin-->>Pipeline: Provide job details to pipeline step
Loading

Poem

In the warren of Jenkins, a new path appears,
Ctrlplane hops in, with jobs and with cheers!
Global configs in many a tongue,
Pollers and listeners, the integration’s begun.
Farewell to old greetings, "Hello World" has retired—
Now agents and pipelines are truly inspired!
🐇✨ With every new build, the future looks bright,
Ctrlplane and Jenkins, together take flight!


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 6

🧹 Nitpick comments (17)
.idea/vcs.xml (1)

1-6: Add a trailing newline for consistency.

The XML content is well structured for version control configuration. However, consider adding a newline at the end of the file to comply with common file formatting standards.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-label.html (1)

1-3: Consistent but Duplicated Help Text

The content is clear; however, it is identical to the help content in help-apiUrl.html. If these files serve different UI roles (for example, one for a label and another for a tooltip), consider differentiating them slightly to better match their context.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly (3)

5-8: Add validation for API URL format.

The API URL field is crucial for the plugin's functionality. Consider adding client-side validation to ensure it's a valid URL format to help users avoid configuration errors.

<f:entry title="API URL" field="apiUrl"
         description="The URL of the Ctrlplane API (e.g., https://app.ctrlplane.dev)">
-    <f:textbox />
+    <f:textbox checkUrl="${descriptor.getCheckUrl('apiUrl')}" />
</f:entry>

You would need to implement the corresponding Java method in your descriptor class:

public FormValidation doCheckApiUrl(@QueryParameter String value) {
    if (StringUtils.isEmpty(value)) {
        return FormValidation.error("API URL cannot be empty");
    }
    try {
        new URL(value);
        return FormValidation.ok();
    } catch (MalformedURLException e) {
        return FormValidation.error("Please enter a valid URL");
    }
}

9-12: Consider adding MaskingPasswordField for better security.

For sensitive information like API keys, Jenkins provides a specialized component that offers enhanced masking capabilities.

<f:entry title="API Key" field="apiKey"
         description="The API key for authenticating with Ctrlplane">
-    <f:password />
+    <f:password class="jenkins-masked-password" />
</f:entry>

21-24: Clarify what happens at minimum polling interval.

The description mentions a minimum of 10 seconds, but users might wonder about the implications of setting it too low.

<f:entry title="Polling Interval (seconds)" field="pollingIntervalSeconds"
-         description="How often to check Ctrlplane for new jobs (minimum 10 seconds).">
+         description="How often to check Ctrlplane for new jobs (minimum 10 seconds to avoid excessive API calls).">
    <f:number default="${descriptor.DEFAULT_POLLING_INTERVAL_SECONDS}" min="10" />
</f:entry>
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (6)

1-33: Consider using static final for constants and ensuring field immutability where possible.
This class introduces two class-level fields (triggeredJobIds and jobAgent) whose access patterns appear mostly read/write by a single polling thread. Marking triggeredJobIds as private final is good for concurrency, but you might consider making the JobAgent reference volatile or re-initialize it if config changes to avoid stale references.


41-48: Validate negative or zero polling intervals.
Currently, if the global configuration sets the polling interval to a nonpositive value, TimeUnit.SECONDS.toMillis(intervalSeconds) could lead to zero or negative scheduling intervals, which might cause thread overhead or unexpected behavior. Consider guarding against invalid intervals.

+ if (intervalSeconds <= 0) {
+     LOGGER.warn("Polling interval must be positive. Setting to default value: {} seconds", 
+         CtrlplaneGlobalConfiguration.DEFAULT_POLLING_INTERVAL_SECONDS);
+     intervalSeconds = CtrlplaneGlobalConfiguration.DEFAULT_POLLING_INTERVAL_SECONDS;
+ }

49-80: Robust config checks but consider parameter logging for easier debugging.
The code gracefully checks if apiUrl, apiKey, and agentName are missing. For debugging, you could log the truncated values (particularly for API URL and agent ID) to help triage incomplete user configurations. Avoid logging the API key for security reasons.


82-95: Re-initialization of jobAgent across config changes.
You note a TODO about reusing the same jobAgent if config changes. If the user updates credentials or API URL, the existing jobAgent might become stale. A safer approach might be to re-instantiate it when crucial configuration changes.


96-117: Consider concurrency or caching to limit repeated polling calls.
If the jobAgent usage evolves, you may want to ensure that repeated calls to getAgentIdString() are cached or handle transient network issues. Current usage looks safe, but keep concurrency and rate-limiting in mind if job volume increases.


231-247: Exception handling is comprehensive but might benefit from more context.
The catch (Exception e) block updates the job status to “FAILED” with a generic reason, which is good for reliability. Consider including the stack trace or a truncated version in the update payload if it helps with debugging.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (5)

34-37: Consider allowing the user to configure the HTTP client version or SSL context.
Although you have a comment noting “Or HTTP_2 if server supports,” the code currently hardcodes HTTP/1.1. If Ctrlplane supports HTTP/2, you could detect and upgrade automatically or allow this to be configurable for performance gains.


72-111: Potential concurrency overlap when registering the agent.
In highly parallel environments, multiple concurrent calls to ensureRegistered could cause multiple PATCH requests if agentIdRef.get() hasn’t yet been updated. Consider using a compare-and-set mechanism or additional locking to avoid duplicate registration attempts.


158-198: Ensure consistent response handling on empty job arrays.
When getNextJobs returns an empty list, the calling code simply proceeds. That’s typically fine. However, double-check that your CtrlplaneJobPoller logic properly differentiates between a genuine “no jobs” response vs. a failed fetch. Consider structured logging or metrics to track partial failures.


208-236: Strengthen error reporting on updateJobStatus.
Currently you log an error when the response code is non-2xx, but you might want to capture and propagate partial server error details (if provided) for troubleshooting.


396-411: Request additional fallback or retry on certain non-2xx responses.
The handleErrorResponse logs the error status code and body but does not attempt any retry logic. Depending on the reliability SLAs of Ctrlplane, consider exponential backoff or limited-retry for transient errors (e.g., 429, 5xx).

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)

118-123: Validate updates to polling interval beyond the UI’s @DataBoundSetter.
You already enforce a minimum of 10 seconds. As a safeguard, consider also logging updates here to detect unexpected changes, especially in ephemeral or container-based Jenkins setups where restarts might revert config.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b5a1ac and 83a3a32.

📒 Files selected for processing (37)
  • .gitignore (1 hunks)
  • .idea/.gitignore (1 hunks)
  • .idea/compiler.xml (1 hunks)
  • .idea/encodings.xml (1 hunks)
  • .idea/jarRepositories.xml (1 hunks)
  • .idea/misc.xml (1 hunks)
  • .idea/vcs.xml (1 hunks)
  • .vscode/settings.json (1 hunks)
  • pom.xml (4 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1 hunks)
  • src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java (0 hunks)
  • src/main/resources/index.jelly (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-credentialsId.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-label.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_de.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_es.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_it.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_pt_BR.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_sv.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_tr.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_zh_CN.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_de.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_de.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/Messages.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/Messages_de.properties (0 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/sample/HelloWorldBuilderTest.java (0 hunks)
💤 Files with no reviewable changes (18)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_de.html
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_tr.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_it.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_sv.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_pt_BR.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_zh_CN.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_es.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_de.html
  • src/main/resources/io/jenkins/plugins/sample/Messages.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_de.properties
  • src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java
  • src/main/resources/io/jenkins/plugins/sample/Messages_de.properties
  • src/test/java/io/jenkins/plugins/sample/HelloWorldBuilderTest.java
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)
  • Extension (24-255)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: security-scan / scan
🔇 Additional comments (25)
.idea/.gitignore (1)

1-9: .idea Gitignore configuration looks solid.

This new file correctly lists the files and directories to ignore—such as /shelf/, /workspace.xml, and /httpRequests/—which helps prevent local IDE and temporary files from being tracked.

.idea/encodings.xml (1)

1-7: UTF-8 encoding configuration is correctly established.

The file sets the encoding to UTF-8 for both source and resource directories, aligning well with standard project-wide practices.

.idea/compiler.xml (1)

1-18: Compiler and annotation processing settings are well-configured.

The XML accurately sets up annotation processing and Javac settings for the ctrlplane-plugin module, with clear output directories. Ensure these settings align with the overall build and module configuration requirements.

.gitignore (1)

26-27: Inclusion of the work/ directory in the ignore list is appropriate.

Adding work/ to the .gitignore prevents temporary or generated files from being committed, aligning with the project's clean repository standards.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl.html (1)

1-3: Clear and Concise API URL Help Content

The HTML snippet clearly informs the user about the purpose of the API URL field and specifies the default URL. It integrates well with the configuration UI and documentation.

.vscode/settings.json (1)

1-3: Automatic Java Build Configuration Enabled

This setting ensures that VSCode automatically updates the Java build configuration, which is useful for maintaining consistency with project dependencies and metadata. Everything looks correct.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-credentialsId.html (1)

1-4: Clear Credentials Configuration Help

The HTML content provides clear instructions to the user about selecting credentials for the Ctrlplane API key and specifies the required "Secret text" type. For improved readability, consider adding visual spacing (e.g., additional <br> tags) if the content appears too dense in the rendered UI.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey.html (1)

1-4: Informative API Key Help Documentation

The snippet effectively guides users on entering the Ctrlplane API key and explains its purpose. The use of paragraph tags enhances readability. This is well-aligned with the overall configuration guidance.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (3)

34-40: Constructor is clear and minimal.
Thanks for overriding the default name in the AsyncPeriodicWork constructor. This approach is concise and straightforward.


119-152: Null checks for critical fields look good.
The code properly checks for valid job ID, jobAgentConfig, and jenkinsJobName. This defensive programming helps ensure partial or malformed jobs are safely skipped. Overall, this portion is well-handled.


249-254: Factory method approach is well-structured.
Allowing an override for testing fosters better testability and mocking. This design pattern is a solid choice.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java (6)

1-16: Class setup is straightforward.
Using JenkinsSessionRule helps ensure fresh Jenkins instances for each test scenario, keeping your tests more stable.


17-26: Documentation is explicit and helpful.
Listing potential pitfalls in the Javadoc is beneficial for future maintainers. Keep it up!


27-48: Initial state checks are thorough.
Verifying defaults (e.g., DEFAULT_API_URL, DEFAULT_AGENT_ID) ensures a strong baseline. This coverage is quite valuable.


50-68: User input simulation for config is clean.
Setting values via HtmlForm fields accurately reflects end-user interaction. This approach boosts confidence in the plugin’s real-world usage.


70-91: Assert accuracy of updated config properties.
These checks tie each property’s new value to the actual storage logic, preventing regressions. Great job.


93-115: Persistence across Jenkins restarts validated.
Testing after a simulated restart is crucial for plugin reliability. This ensures no unexpected resets or data loss.

pom.xml (5)

17-17: Project name updated successfully.
Renaming to "Ctrlplane Plugin" aligns with the new plugin’s identity.


35-36: Updated Jenkins baseline and version.
Ensure you have tested your code on Jenkins 2.492.3 or later so that newly introduced features or APIs are properly supported.


45-46: Refers to a new BOM version.
Ensure that 4051.v78dce3ce8b_d6 is suitable for this Jenkins baseline and that no transitive dependency conflicts arise.


55-58: Added jackson-databind with version 2.15.3.
Keep an eye on security advisories for jackson-databind, as vulnerabilities historically appear in certain versions.


8-8:

❓ Verification inconclusive

Parent plugin version bump.
Confirm that version 5.7 is compatible with your targeted Jenkins baseline to avoid build or dependency conflicts.


🏁 Script executed:

#!/bin/bash
# Checking known plugin POM versions and any possible compatibility issues
rg -A 3 'jenkins.baseline'

Length of output: 526


Parent Plugin Version Bump – Please Verify Compatibility

The parent plugin version in pom.xml has been updated to 5.7 (line 8). Based on the current POM settings (with <jenkins.baseline>2.492</jenkins.baseline> and <jenkins.version>${jenkins.baseline}.3</jenkins.version>), please verify that this version bump won’t introduce any build or dependency conflicts with your targeted Jenkins baseline. Ensure that any downstream components or BOM imports aligning with ${jenkins.baseline} continue to work as expected.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

118-142: Unused method: createAgentConfig.
The method is not invoked anywhere and the “type” field differs (“exec-windows”) from the “jenkins” type in ensureRegistered. If you plan to eventually send agent configuration, consider hooking this method into your registration. Otherwise, remove it to reduce confusion.

Do you intend to use the config payload in the immediate future? If not, we can remove it. Let me know if you'd like a quick cleanup.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (2)

36-46: Ensure values are reloaded properly after restart.
The constructor sets defaults if the configuration is missing. This is correct. Also confirm that user-provided settings are respected if present. Good usage of StringUtils.isBlank and your default fallbacks.


125-165: Good coverage of form validations.
Your FormValidation methods provide clear warnings and usage hints. This should help prevent misconfiguration.

Comment on lines +30 to +34
private String apiUrl;
private String apiKey;
private String agentId;
private String agentWorkspaceId;
private int pollingIntervalSeconds;
Copy link
Contributor

@coderabbitai coderabbitai bot Apr 12, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Store apiKey more securely if possible.
Jenkins offers integration with the Credentials Plugin for sensitive data. Especially for production, consider referencing a credentials ID instead of storing raw secrets in global configuration.

- private String apiKey;
+ private String credentialsId; // Then retrieve the token from Jenkins Credentials Manager
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private String apiUrl;
private String apiKey;
private String agentId;
private String agentWorkspaceId;
private int pollingIntervalSeconds;
private String apiUrl;
private String credentialsId; // Then retrieve the token from Jenkins Credentials Manager
private String agentId;
private String agentWorkspaceId;
private int pollingIntervalSeconds;

Copy link
Member Author

Choose a reason for hiding this comment

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

Valid, but we need to integrate with the jenkins credentials plugin.
https://plugins.jenkins.io/credentials/

If you have ideas of how to do that @coderabbitai would love to take them into consideration. Or maybe you can make a followup issue and pr to address that issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

No description provided.

zacharyblasczyk and others added 2 commits April 12, 2025 02:16
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@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: 0

♻️ Duplicate comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

28-30: Avoid unbounded memory growth in the triggeredJobIds map.

This map might grow indefinitely over time because there's no cleanup mechanism for completed or expired jobs. Consider removing stale entries after the job finishes or implementing a time-based cleanup to avoid potential memory leaks.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

40-40: API key might be stored insecurely.

Storing the API key as a plain string can pose security risks. Whenever possible, rely on Jenkins Credentials and mask them in logs rather than storing them in plain text.

🧹 Nitpick comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

227-227: Use the explicit return type instead of Object.

scheduleBuild2 returns a QueueTaskFuture<?>, so replacing the Object type with QueueTaskFuture<?> is more descriptive and helps with type checking and readability.

- Object future = jenkinsJob.scheduleBuild2(0, paramsAction);
+ QueueTaskFuture<?> future = jenkinsJob.scheduleBuild2(0, paramsAction);
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

117-141: Consider removing or using the createAgentConfig method.

This method is never called, so it adds unused code. If it’s reserved for future enhancements, leaving a comment clarifying its intent can help maintainers. Otherwise, consider removing it to keep the class minimal.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 435d748 and 2a7ee87.

📒 Files selected for processing (2)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)
  • Extension (14-167)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (29-473)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: security-scan / scan
🔇 Additional comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

1-357: Overall, implementation looks solid.

The polling workflow, logging, and error-handling are well-structured. Good job ensuring robust checks for null or invalid data. The usage of AsyncPeriodicWork and concurrency mechanisms is generally correct.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

1-474: No other immediate issues detected.

HTTP request handling, JSON parsing, and response processing are well-structured. Logging is detailed enough for troubleshooting. Great job on this implementation!

Copy link
Contributor

@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: 1

♻️ Duplicate comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)

28-29: Avoid indefinite growth of triggeredJobIds.

A similar concern was raised previously regarding the potential for unbounded memory growth if old job IDs are never removed from triggeredJobIds.


201-228: 🛠️ Refactor suggestion

Implement a cleanup mechanism for successfully triggered jobs.

Currently, triggeredJobIds only grows as new jobs are triggered, and we never remove them after builds complete. Use a Jenkins RunListener or a time-based strategy to prune old entries—particularly beneficial for long-running or frequently triggered jobs.

+ // Example: Expose a removal method in CtrlplaneJobPoller and call it from a RunListener when the job finishes.
+ public static void removeTriggeredJobId(String jobId) {
+     triggeredJobIds.remove(jobId);
+ }
🧹 Nitpick comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)

49-51: Avoid catching generic Exception whenever possible.

Catching Exception can obscure more specific errors and make debugging harder. Consider catching narrower exceptions or rethrowing unhandled ones for better clarity.


94-101: Re-initialize jobAgent if global configuration changes.

Currently, jobAgent is created only once. If a user updates Ctrlplane settings (e.g., apiKey, apiUrl), the agent won’t be rebuilt. Consider re-creating the agent when the configuration changes, or at least verifying the agent’s parameters remain valid.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a7ee87 and e2d86d6.

📒 Files selected for processing (1)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: security-scan / scan
🔇 Additional comments (1)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

54-75: Consider adding dedicated tests for the polling flow.

While we see logic for polling and processing jobs, there is no direct unit or integration test class that targets CtrlplaneJobPoller. Test coverage would help ensure reliability and detect regressions early.

Would you like assistance in generating a basic test harness for this poller?

Copy link
Contributor

@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: 4

♻️ Duplicate comments (4)
src/utils/CtrlplaneClient.groovy (1)

50-51: 🛠️ Refactor suggestion

Consider using Jenkins credentials for the API key.

Storing sensitive API keys as plain strings can pose security risks. Jenkins provides a credentials system that better protects secrets from exposure.

Previous reviews have noted this concern. Consider implementing a solution that leverages the Jenkins Credentials API to securely store and retrieve the API key.

// In the method signature
- def getJob(String jobId, String baseUrl = 'https://api.example.com', String apiKey = null) {
+ def getJob(String jobId, String baseUrl = 'https://api.example.com', Secret apiKey = null) {

// When using the key
- connection.setRequestProperty('X-API-Key', apiKey)
+ connection.setRequestProperty('X-API-Key', apiKey.getPlainText())
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)

37-37: Potential memory growth in activeJenkinsJobs.

The activeJenkinsJobs map could grow indefinitely as new jobs are triggered, potentially leading to memory issues over time.

Similar concerns were raised in previous reviews about the triggeredJobIds map. While you're using iterator.remove() in the reconciliation method, consider adding an additional cleanup mechanism for jobs that might get "stuck" in active status or adding time-based expiration.

#!/bin/bash
# Check if there's any explicit cleanup mechanism for the activeJenkinsJobs map
# beyond the iterator.remove() calls in the reconciliation method

rg "activeJenkinsJobs\.clear|activeJenkinsJobs\.remove" --type java

635-636: ⚠️ Potential issue

Store apiKey using Jenkins Secret API.

Storing sensitive information like API keys as plain strings can lead to security vulnerabilities, especially when serialized to disk.

Previous security scans have flagged this issue. Use Jenkins' Secret type or leverage the Credentials API to securely store the API key.

- final String apiKey;
+ final Secret apiKey;
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

38-40: ⚠️ Potential issue

Sensitive credential is stored as a plain string field.

The apiKey field is potentially storing a sensitive credential as a plain string, which could be exposed if the object is serialized or printed. This matches the security warning flagged in previous reviews.

Consider implementing the following security improvements:

  1. Use Jenkins' Secret class for sensitive credentials storage
  2. Mark the field as transient to prevent serialization
-    private final String apiKey;
+    private final transient Secret apiKey;

And update the constructor to accept and store the Secret:

-    public JobAgent(String apiUrl, String apiKey, String name, String agentWorkspaceId) {
+    public JobAgent(String apiUrl, Secret apiKey, String name, String agentWorkspaceId) {
🧹 Nitpick comments (15)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (3)

27-37: Consider logging a more descriptive message for ignored jobs.

Currently, if the JOB_ID parameter is absent, the code silently returns, which might make troubleshooting harder. Logging a brief message (e.g., "Skipping Ctrlplane update: no JOB_ID parameter found") can clarify why the update was skipped.


39-70: Evaluate caching or reusing the JobAgent instance for performance.

Recreating the JobAgent each time a build completes is acceptable for smaller loads but might introduce overhead at scale. Consider creating or reusing a singleton or cached instance if performance or configuration loading time becomes a concern.


82-106: Handle corner-case results more explicitly.

The method defaults unknown Jenkins results to "failure". If future Jenkins results (like downstream test failures or custom statuses) appear, consider logging an informational warning instead of silently marking them as failures, to avoid debugging confusion.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (2)

60-68: Expand test coverage for edge-case URLs.

While this test verifies typical Jenkins job URLs, consider adding malformed or more complex URL patterns (e.g., trailing spaces or unusual patterns) to ensure robust parsing and error handling.


70-89: Enhance verification of job status updates.

The test only asserts that the mock's updateJobStatus method was called with certain arguments. For stronger validation, consider verifying additional details, such as the presence or absence of a "message", if that is also used in other parts of the workflow.

src/main/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStep.java (3)

33-42: Validate constructor argument beyond UUID format.

While the UUID format check is excellent, consider also confirming the job ID's relevance in your system. For instance, you might check if the job ID references an active job or has valid permissions, if applicable.


92-101: Consider catching more specific exceptions.

The code catches IllegalArgumentException to handle invalid UUIDs. If the step can fail for other reasons during parsing or retrieval, consider adding narrower exception handling (e.g., NumberFormatException) or clarifying error messages to better guide the user.


123-133: Clarify null return conditions in logs and messages.

When getJob(jobUUID) returns null, the code aborts with a generic message. To ease troubleshooting, consider logging or including more contextual info (e.g., status code from any HTTP request). This helps identify external API or configuration issues quickly.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (7)

155-173: Optimize agent registration check flow.

The code has redundant checks for agent ID that could be simplified. After ensureRegistered() returns true, it rechecks agentIdRef.get() and performs additional error handling that should never be reached.

    public List<Map<String, Object>> getNextJobs() {
        String agentId = agentIdRef.get();
        if (agentId == null) {
            // ensureRegistered will now attempt registration AND set the ID if successful.
            if (!ensureRegistered()) {
                // ensureRegistered logs the specific error (request failed or no ID in response)
                LOGGER.error("Cannot get jobs: Agent registration/upsert failed or did not provide an ID.");
                return Collections.emptyList();
            }
-            // Re-check if agentId was set by ensureRegistered
-            agentId = agentIdRef.get();
-            if (agentId == null) {
-                // This condition should technically not be reachable if ensureRegistered returned true,
-                // as true implies the agentIdRef was set. Log an internal error if it happens.
-                LOGGER.error(
-                        "Internal error: ensureRegistered returned true but agent ID is still null. Cannot get jobs.");
-                return Collections.emptyList();
-            }
+            // If we get here, ensureRegistered succeeded and agentId should be set
+            agentId = agentIdRef.get();
+            assert agentId != null : "ensureRegistered returned true but agent ID is still null";
        }

205-209: Add null check for details parameter.

The updateJobStatus method validates jobId and status but doesn't check if details is null before using it later in the method. Although the method handles the case where details is null in specific sections, adding an explicit null check at the beginning would be clearer.

    public boolean updateJobStatus(UUID jobId, String status, Map<String, Object> details) {
        if (jobId == null || status == null || status.isBlank()) {
            LOGGER.error("Invalid input for updateJobStatus: Job ID and Status are required.");
            return false;
        }
+       
+        // Initialize details to empty map if null to simplify later code
+        details = details != null ? details : Collections.emptyMap();

219-251: Simplify conditional logic when extracting message.

The message extraction logic contains redundant null checks and could be simplified by using the previously suggested empty map initialization.

-        if (details != null && !details.isEmpty()) {
+        // Extract external ID if present
+        if (details.containsKey("externalId")) {
+            externalId = details.get("externalId").toString();
+            requestBody.put("externalId", externalId);
+        }
+        
+        // Extract message using a priority order of checks
+        if (details.containsKey("message")) {
+            message = details.get("message").toString();
+        } else if (details.containsKey("trigger")) {
+            message = "Triggered by: " + details.get("trigger");
+        } else if (details.containsKey("reason")) {
+            message = details.get("reason").toString();
+        }
+        
+        if (message != null) {
+            requestBody.put("message", message);
+        }
+        
+        // Check for ctrlplane/links metadata
+        if (details.containsKey("ctrlplane/links")) {
+            Object linksObj = details.get("ctrlplane/links");
+            if (linksObj instanceof Map) {
+                requestBody.put("ctrlplane/links", linksObj);
+            } else {
+                LOGGER.warn(
+                        "Value for 'ctrlplane/links' in details map is not a Map for job {}. Skipping links.", jobId);
+            }
+        }
-            // Check for external ID in details
-            if (details.containsKey("externalId")) {
-                externalId = details.get("externalId").toString();
-                requestBody.put("externalId", externalId);
-            }
-
-            // Extract message if present, otherwise use trigger as message
-            if (details.containsKey("message")) {
-                message = details.get("message").toString();
-            } else if (details.containsKey("trigger")) {
-                message = "Triggered by: " + details.get("trigger");
-            } else if (details.containsKey("reason")) {
-                message = details.get("reason").toString();
-            }
-
-            if (message != null) {
-                requestBody.put("message", message);
-            }
-        }
-
-        // Check for ctrlplane/links metadata
-        if (details != null && details.containsKey("ctrlplane/links")) {
-            Object linksObj = details.get("ctrlplane/links");
-            if (linksObj instanceof Map) {
-                // Assuming the value is Map<String, String>, but API expects Map<String, Object>
-                // No explicit cast needed as Map is compatible.
-                requestBody.put("ctrlplane/links", linksObj);
-            } else {
-                LOGGER.warn(
-                        "Value for 'ctrlplane/links' in details map is not a Map for job {}. Skipping links.", jobId);
-            }
-        }

325-329: Use try-with-resources for AutoCloseable resources.

The catch block correctly restores the interrupt status when an InterruptedException is caught, but similar handling should be applied in all other catch blocks that catch InterruptedException.

Implement consistent interrupt status handling across the class for all methods that catch InterruptedException.


386-400: Improve URI building logic.

The URI building logic makes assumptions about the API endpoint structure that may not always be valid. Consider enhancing the logic to handle more URL formats and edge cases.

    private URI buildUri(String path) throws URISyntaxException, MalformedURLException {
        String cleanApiUrl =
                this.apiUrl.endsWith("/") ? this.apiUrl.substring(0, this.apiUrl.length() - 1) : this.apiUrl;
        String cleanPath = path.startsWith("/") ? path : "/" + path;

-        // Ensure /api/v1 structure
+        // Build the final URL based on the API URL structure
         String finalUrlString;
-        if (cleanApiUrl.endsWith("/api")) {
-            finalUrlString = cleanApiUrl + cleanPath; // Assumes path starts with /v1
+        if (cleanApiUrl.endsWith("/api") || cleanApiUrl.contains("/api/")) {
+            // The API URL already contains the /api path
+            finalUrlString = cleanApiUrl + cleanPath;
         } else {
             finalUrlString = cleanApiUrl + "/api" + cleanPath;
         }
+        LOGGER.debug("Built URI: {}", finalUrlString);
         return new URI(finalUrlString);
    }

463-478: Enhance error response handling.

The error response handling could be improved to extract more structured error information from the API response, assuming the API returns error details in a standard format.

Consider parsing the error response body as JSON when possible to extract more detailed error information:

    private void handleErrorResponse(HttpResponse<InputStream> response, int statusCode) {
        String errorBody = "<Could not read error body>";
        try (InputStream es = response.body()) { // Body might contain error details even on non-2xx
            if (es != null) {
                errorBody = new String(es.readAllBytes(), StandardCharsets.UTF_8);
+               
+               // Try to parse error body as JSON for more structured error info
+               try {
+                   Map<String, Object> errorMap = objectMapper.readValue(errorBody, 
+                       new TypeReference<Map<String, Object>>() {});
+                   
+                   if (errorMap.containsKey("error") || errorMap.containsKey("message")) {
+                       String errorMessage = (String) errorMap.getOrDefault("error", 
+                           errorMap.getOrDefault("message", "Unknown error"));
+                       LOGGER.error(
+                           "HTTP Error: {} - URL: {} - Error: {}",
+                           statusCode,
+                           response.uri(),
+                           errorMessage);
+                       return;
+                   }
+               } catch (IOException e) {
+                   // Failed to parse as JSON, fall back to logging raw response
+                   LOGGER.debug("Could not parse error response as JSON: {}", e.getMessage());
+               }
            }
        } catch (IOException e) {
            LOGGER.warn("Could not read error response body: {}", e.getMessage());
        }

        LOGGER.error(
                "HTTP Error: {} - URL: {} - Response: {}",
                statusCode,
                response.uri(), // Use URI from response
                errorBody);
    }

538-541: Consider implementing a Job response class.

Using Map<String, Object> for job representation works for simple cases but lacks type safety. As noted in the comment, a JobResponse inner class would be beneficial as the project matures.

Consider implementing a proper JobResponse class to provide:

  1. Type safety for job fields
  2. Documentation of the expected job structure
  3. Better IDE support and code completion
  4. Clearer API contracts

This would improve maintenance and readability, especially as the project grows.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2d86d6 and 4cd10b4.

📒 Files selected for processing (9)
  • example.Jenkinsfile (1 hunks)
  • pom.xml (4 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStep.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java (1 hunks)
  • src/utils/CtrlplaneClient.groovy (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pom.xml
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (3)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)
  • Extension (21-145)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)
  • Extension (14-167)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (29-541)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)
  • Extension (33-761)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (29-541)
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)
  • JobInfo (668-678)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (29-541)
src/main/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStep.java (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)
  • Extension (21-145)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (29-541)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: security-scan / scan
🔇 Additional comments (8)
src/utils/CtrlplaneClient.groovy (1)

50-51:

✅ Verification successful

Authentication method changed from Bearer token to API key header.

The API authentication method has been updated to use the X-API-Key header instead of what was likely a Bearer token approach. This change aligns with the API's expected authentication format but introduces security considerations.


🏁 Script executed:

#!/bin/bash
# Check if there are any other places in the codebase where API calls are made
# to ensure consistent authentication method is used

# Look for places where HTTP requests are made
rg "openConnection|HttpURLConnection|HttpClient" --type groovy --type java

Length of output: 771


Authentication Method Update Verification

The authentication update in src/utils/CtrlplaneClient.groovy—changing from using a Bearer token to setting the X-API-Key header—is correctly applied (see lines 50–51). Our review of the repository shows that while this Groovy client uses the updated header, other HTTP client implementations (e.g., in src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java) rely on Java’s HttpClient without similar authentication handling. There are no conflicting usages of the older Bearer token approach, but please ensure that all API integrations are consistent and that any downstream dependencies properly handle the API key authentication method.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)

104-108: Good use of method documentation and early returns.

The method initializeAndRegisterAgent has clear documentation explaining its purpose, parameters, return value, and the use of early returns for failure cases, which improves code readability and robustness.


154-159: Comprehensive job reconciliation approach.

The reconciliation logic for tracking jobs across Jenkins restarts is well-designed and addresses an important edge case where the RunListener might not fire during restart, ensuring job statuses are properly updated in Ctrlplane.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java (1)

17-67: Comprehensive URL parsing tests.

The test cases for extractJobNameFromUrl cover a wide range of scenarios, including simple URLs, nested URLs, URLs with context paths, complex folder structures, and invalid/edge cases. This thorough testing helps ensure the URL parsing is robust.

example.Jenkinsfile (3)

6-8: Simplified parameters section.

The parameters have been simplified by removing the API_URL parameter, which is now handled by the plugin configuration. This makes the pipeline cleaner and easier to use.


18-24: Improved job details retrieval with the ctrlplaneGetJob step.

The job retrieval has been simplified to use the built-in ctrlplaneGetJob step instead of loading a script and using a custom client. This approach is cleaner and more aligned with Jenkins Pipeline's declarative style.


26-35: Helpful examples for accessing job details.

The commented examples show users how to access specific fields from the job details response, which is helpful for adoption and understanding how to use the plugin.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (1)

131-160: Add negative testing for update failures.

All current tests assume updateJobStatus returning true. Consider a test scenario where updateJobStatus fails (returns false), and verify that the poller handles or logs the failure properly. This ensures better resilience.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)

104-107: Use Jenkins credentials for managing API key securely.

Storing the apiKey string in configuration risks exposing secrets in plain text. This was previously flagged and remains valid. Adopting Jenkins credentials (e.g., using a Secret or CredentialsBinding) for apiKey is recommended to mitigate security risks.


262-265: ⚠️ Potential issue

Avoid returning early on null build result to continue reconciling other jobs.

If one job's Run has a null Result, line 264 ends the entire reconciliation early, skipping all subsequent jobs in the loop. Consider changing return; to continue; instead:

- if (result == null) {
-     return;
- }
+ if (result == null) {
+     LOGGER.debug("Jenkins job '{}' has a null result during reconciliation. Skipping this job.", ctrlplaneJobId);
+     continue;
+ }
🧹 Nitpick comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)

37-37: Consider a fallback cleanup for indefinitely queued jobs.

Although you remove entries for concluded or missing jobs, a job stuck indefinitely or never fully scheduled may linger in activeJenkinsJobs. As a precaution, you could introduce a time-based or periodic cleanup to further prevent memory growth.


604-642: Validate deeper nested paths for multi-branch and folder-based jobs.

Although searching for "/job/" in extractJobNameFromUrl works for standard paths, multi-branch or deeply nested folder jobs can have multiple segments. You may need to handle repeated "/job/" tokens or complex path structures to ensure correct job name extraction.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd10b4 and a02c5ba.

📒 Files selected for processing (1)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (3)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)
  • Extension (14-167)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)
  • Extension (21-145)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (29-541)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: security-scan / scan

Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
CONTRIBUTING.md (1)

10-10: Clarify Spotless Maven Plugin usage for formatting.

The instruction "Consider using mvn spotless:apply verify to format your code" could be clearer. If you intend contributors to both format and verify, consider splitting into two commands or clarifying the sequence, e.g.:

Run mvn spotless:apply to format your code, and mvn spotless:check to verify formatting.

This helps avoid confusion for new contributors.

🧰 Tools
🪛 LanguageTool

[grammar] ~10-~10: Probably a preposition is missing after ‘apply’.
Context: ...the existing code style. Consider using mvn spotless:apply verify to format your code. * Add unit ...

(ATD_VERBS_TO_COLLOCATION)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec977f2 and 523ebcf.

📒 Files selected for processing (5)
  • .github/CODEOWNERS (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • Jenkinsfile (1 hunks)
  • README.md (1 hunks)
  • pom.xml (3 hunks)
✅ Files skipped from review due to trivial changes (3)
  • Jenkinsfile
  • .github/CODEOWNERS
  • README.md
🧰 Additional context used
🪛 LanguageTool
CONTRIBUTING.md

[grammar] ~10-~10: Probably a preposition is missing after ‘apply’.
Context: ...the existing code style. Consider using mvn spotless:apply verify to format your code. * Add unit ...

(ATD_VERBS_TO_COLLOCATION)


[style] ~26-~26: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1581 characters long)
Context: ...issue. Thank you for your contributions!

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (6)
pom.xml (5)

8-8: Verify compatibility and security of updated dependencies and Jenkins baseline.

The updates to the parent plugin version, Jenkins baseline, and pinned dependencies (e.g., jackson-databind, mockito-core) are appropriate for the new plugin architecture. However, please verify that:

  • All dependencies are compatible with Jenkins 2.492+ and plugin parent 5.9.
  • The pinned versions of dependencies (especially jackson-databind and mockito-core) are free from known security vulnerabilities.

Consider running a dependency check or using tools like mvn versions:display-dependency-updates and mvn dependency-check:check to ensure all dependencies are up to date and secure.

Also applies to: 62-63, 83-85, 101-103


26-51: Developers section is well-structured and informative.

The <developers> section is clear, provides contact information, and follows Maven conventions. This will help with project maintainability and transparency.


65-65: Repository and SCM URLs updated correctly.

The GitHub repository and SCM URLs have been updated to reflect the new project location. This ensures that contributors and automation tools reference the correct repository.

Also applies to: 18-18, 53-56


73-74: BOM artifact and version updated for Jenkins baseline.

The BOM artifact and version are now aligned with the new Jenkins baseline. This helps ensure dependency compatibility and reduces the risk of version conflicts.


89-90: Dependency scopes and artifact choices are appropriate for new plugin structure.

  • structs is now compile scope, which is correct for pipeline integration.
  • workflow-step-api is used instead of heavier workflow dependencies, which is a best practice for step plugins.
  • jenkins-test-harness and mockito-core are correctly scoped for testing.

Also applies to: 93-94, 97-98, 102-104

CONTRIBUTING.md (1)

1-27: Contribution guide is clear, welcoming, and comprehensive.

The steps for contributing, code style enforcement, and encouragement to add tests are well-articulated. The tone is friendly and the instructions are actionable, which will help onboard new contributors smoothly.

🧰 Tools
🪛 LanguageTool

[grammar] ~10-~10: Probably a preposition is missing after ‘apply’.
Context: ...the existing code style. Consider using mvn spotless:apply verify to format your code. * Add unit ...

(ATD_VERBS_TO_COLLOCATION)


[style] ~26-~26: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1581 characters long)
Context: ...issue. Thank you for your contributions!

(EN_EXCESSIVE_EXCLAMATION)

Copy link
Contributor

@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: 1

♻️ Duplicate comments (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)

118-132: [Duplicate with a stronger emphasis on best practices for credential handling]

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

36-39: 🛠️ Refactor suggestion

Plaintext storage of the apiKey.

The apiKey field should be stored using Jenkins credentials to avoid exposing secrets. Consider referencing a credentialsId and retrieving the actual key at runtime.

🧹 Nitpick comments (5)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (2)

60-71: Inform user when JobAgent creation fails.

Early returning after logging in createJobAgent == null scenario is a good fail-fast mechanism. However, consider displaying a user-facing error or hint. Relying entirely on logs may mask errors in headless or automated Jenkins deployments.


118-132: Validate agent configuration earlier.

Creating the JobAgent only logs an error if the API URL or key are missing. For fail-fast behavior, consider throwing an exception or prompting the user more directly instead of silently returning null.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

55-73: Separate concerns in the execute() method.

The execute() method handles configuration validation, registration, reconciliation, and polling. Consider extracting these steps into smaller private methods or classes to improve maintainability and testability.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (2)

79-97: Handle missing workspace ID more gracefully.

You return false if the workspace ID is missing, hindering agent registration. Consider distinct logging clarifications or user feedback about the cause.


355-364: Ensure consistent retry or fallback.

When httpClient.send() fails, the code logs an error and returns null. Consider implementing a retry mechanism or fallback behavior, especially for transient network issues.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 523ebcf and 931601d.

📒 Files selected for processing (41)
  • pom.xml (3 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1 hunks)
  • src/main/resources/index.jelly (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_de.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_es.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_fr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_it.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_pt_BR.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_sv.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_tr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_zh_CN.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_de.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_es.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_fr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_it.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_pt_BR.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_sv.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_tr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_zh_CN.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_de.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_es.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_fr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_it.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_pt_BR.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_sv.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_tr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_zh_CN.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_de.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_es.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_fr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_it.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_pt_BR.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_sv.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_tr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_zh_CN.properties (1 hunks)
✅ Files skipped from review due to trivial changes (34)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_it.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_de.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_de.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_sv.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_zh_CN.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_es.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_sv.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_zh_CN.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_tr.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_pt_BR.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_it.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_it.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_fr.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_pt_BR.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_fr.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_tr.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_zh_CN.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_sv.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_fr.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_es.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_fr.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_de.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_pt_BR.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_de.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_zh_CN.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_es.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_sv.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_it.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_tr.html
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_pt_BR.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_tr.properties
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_es.properties
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/resources/index.jelly
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java
🧰 Additional context used
🧠 Learnings (2)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: security-scan / scan
🔇 Additional comments (11)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (2)

35-47: Graceful early return on missing Ctrlplane Job ID.

The conditional check for ctrlplaneJobId == null provides a clean and safe early return for jobs not triggered by Ctrlplane. This helps avoid unnecessary API calls and potential errors.


118-132: 🛠️ Refactor suggestion

Use Jenkins credentials for API key.

Currently, apiKey is read directly from the global config. Storing credentials in plain text can introduce security risks. A recommended approach is to replace direct apiKey usage with a credentials ID and retrieve the secret securely at runtime via Jenkins CredentialsProvider.

⛔ Skipped due to learnings
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (4)

36-36: ConcurrentHashMap usage is appropriate for active job tracking.

The use of ConcurrentHashMap<String, ActiveJobInfo> ensures thread safety when multiple threads potentially access active Jenkins job data in the poller.


74-85: Efficient skipping when no pending jobs are found.

Early return after verifying the pending jobs list is null or empty is a clean approach that avoids unnecessary processing.


168-210: Timely cleanup of completed jobs.

Removing completed or failed jobs from activeJenkinsJobs using iterator.remove() prevents indefinite growth in memory usage, which is essential for long-running Jenkins instances. Consider a time-based or build completion-based approach if there are any edge cases not covered here.


463-485: Validate job ID uniqueness for queued items.

When searching for the matching queue item by JOB_ID, the code breaks upon finding the first match. If queued multiple times for the same job ID, ensure this logic meets your intended behavior (usually, only a single queued item should exist, but verifying assumptions can prevent potential duplication issues).

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (2)

31-34: Reasonable default HTTP client configuration.

Using a 10-second connectTimeout is typically sufficient, and HTTP/1.1 ensures broad compatibility.


491-503: Log minimal error body on failures.

Capturing error response bodies is helpful for diagnostics. Just ensure they don’t contain sensitive data. Logging entire bodies unfiltered can present security or privacy issues, so remember to sanitize or filter sensitive info if necessary.

pom.xml (3)

8-8: Project modernization and metadata updates look good.

Upgrading the parent version, updating the project name, and adding developer information are all positive steps for maintainability and clarity. These changes align the plugin with its new purpose and ownership.

Also applies to: 17-17, 26-37


48-51: Jenkins baseline and BOM version update: verify compatibility.

Raising the Jenkins baseline and updating the BOM version are necessary for using newer Jenkins APIs and features. However, ensure that all plugin code and dependencies are compatible with Jenkins 2.492+ and the new BOM. Some plugins or libraries may have breaking changes or require migration steps.

Would you like a script to check for deprecated or incompatible APIs in your Java sources?

Also applies to: 59-61


51-51: Repository and artifactId update: ensure consistency across the codebase.

The GitHub repository and artifactId have been updated to reflect the new plugin identity. Make sure all references in documentation, Java package names, and Jenkins plugin metadata are consistent with these changes.

Would you like a script to search for old artifactId or repo references in your codebase?

Also applies to: 13-13, 18-18

.build();

private final String apiUrl;
private final String apiKey;

Check warning

Code scanning / Jenkins Security Scan

Jenkins: Plaintext password storage Warning

Field should be reviewed whether it stores a password and is serialized to disk: apiKey
@zacharyblasczyk zacharyblasczyk requested a review from jsbroks April 15, 2025 01:26
@zacharyblasczyk
Copy link
Member Author

@coderabbitai full review

Copy link
Contributor

coderabbitai bot commented Apr 15, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@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: 2

♻️ Duplicate comments (4)
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java (1)

69-92: Placeholder test remains to be implemented.

There's a commented example for the testTriggerJenkinsJobWithParameters method, but no actual implementation. Based on previous review comments, I see this has already been tracked with a GitHub issue for future implementation using PowerMock.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)

66-71: Consider throwing an exception for missing configuration.

Revisiting a prior suggestion: returning null from createJobAgent() and only logging an error may cause silent failures when critical data is missing. For improved fail-fast behavior and clearer user feedback, consider throwing a runtime exception or surfacing the error to the Jenkins UI.

src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)

37-37: ⚠️ Potential issue

Store the API key using Jenkins credentials.

Storing the API key in a plaintext field raises security concerns, as flagged by static analysis and prior learnings. To enhance security, consider using the Jenkins credentials plugin by replacing apiKey with a credentials ID and retrieving the actual secret at runtime.

Example partial diff:

- private final String apiKey;
+ private final String credentialsId;

 public JobAgent(String apiUrl, String credentialsId, String name, String agentWorkspaceId) {
-    this.apiKey = apiKey;
+    this.credentialsId = credentialsId;
     ...
 }
🧰 Tools
🪛 GitHub Check: Jenkins Security Scan

[warning] 37-37: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)

28-28: 🛠️ Refactor suggestion

Store apiKey more securely using Jenkins credentials.

Storing apiKey in plain text may expose secrets in configuration files and Jenkins system logs. As per [retrieved_learnings], consider using a credentialsId field and leveraging the Jenkins Credentials Plugin to fetch the actual secret at runtime.

🧰 Tools
🪛 GitHub Check: Jenkins Security Scan

[warning] 28-28: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey

🧹 Nitpick comments (10)
CONTRIBUTING.md (2)

10-10: Clarify Spotless usage for code formatting.

The phrase "mvn spotless:apply verify" may be confusing. For clarity, suggest splitting into two commands:

  • "mvn spotless:apply" (to format your code)
  • "mvn verify" (to check code style and run tests)

This helps contributors understand the correct workflow.

-    *   Adhere to the existing code style. Consider using `mvn spotless:apply verify` to format your code.
+    *   Adhere to the existing code style. Run `mvn spotless:apply` to format your code, and `mvn verify` to check code style and run tests.
🧰 Tools
🪛 LanguageTool

[grammar] ~10-~10: Probably a preposition is missing after ‘apply’.
Context: ...the existing code style. Consider using mvn spotless:apply verify to format your code. * Add unit ...

(ATD_VERBS_TO_COLLOCATION)


11-11: Optional: Add a comma for readability.

Consider adding a comma after "if applicable" for improved readability.

-    *   Add unit tests for new functionality or bug fixes if applicable.
+    *   Add unit tests for new functionality or bug fixes, if applicable.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~11-~11: Possible missing comma found.
Context: ...unit tests for new functionality or bug fixes if applicable. 4. Test: Build the ...

(AI_HYDRA_LEO_MISSING_COMMA)

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (2)

60-68: Concise URL parsing tests.

These tests validate the same functionality as in CtrlplaneJobPollerTest but in a more concise manner. Consider consolidating these tests into one class to avoid duplication.


131-160: Effective use of ArgumentCaptor for verification.

This test demonstrates good use of ArgumentCaptor to capture and verify the contents of the details map passed to updateJobStatus. This approach allows thorough verification of complex parameters.

One minor observation: There's a redundant capture at line 149 after already capturing at line 144, which doesn't affect the test but could be simplified.

- verify(jobAgent).updateJobStatus(eq(jobUUID), eq("in_progress"), detailsCaptor.capture());
+ verify(jobAgent).updateJobStatus(eq(jobUUID), eq("in_progress"), any());
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)

80-81: Consider limiting log message size.

While adding an informative message to details is helpful, logging a large or unbounded message could clutter logs. Consider truncating or sanitizing overly long messages to keep logs manageable.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (3)

36-36: Ensure eventual cleanup or time-based eviction for activeJenkinsJobs.

While you remove entries upon job completion in reconcileInProgressJobs(), consider whether there are scenarios where entries might never be removed (e.g., a job that is queued or stuck indefinitely). A time-based eviction policy or additional reconciliation checks for stale entries could help maintain memory safety in long-running Jenkins instances.


175-208: Concurrent iteration on ConcurrentHashMap entries.

Using iterator.remove() is valid, but be aware that concurrent modifications by other threads during iteration may cause missed entries or partial reconciliation. If strict consistency is needed, consider external synchronization or capturing a snapshot of activeJenkinsJobs before iteration.


613-659: Robust logic for extracting Jenkins job name from URLs.

The incremental checks and transformations (e.g., trimming trailing slash, searching for /job/, and replacing) reduce parsing errors. Consider adding unit tests for edge cases (double slashes, unusual job paths, etc.).

pom.xml (1)

69-71: Added and reorganized dependencies (Jackson, structs, workflow-step-api, test harness, Mockito).

These changes appear consistent with your new plugin functionality (JSON processing, pipeline steps, testing). Double-check for potential version conflicts, especially with jackson-databind, as it updates frequently.

To confirm no duplicates or conflicts, you may run:

+ mvn dependency:tree

Also applies to: 74-75, 79-79, 82-83, 87-89

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)

54-54: Saving configuration on each property change.

Calling save() within each setter ensures immediate persistence but can be chatty. If multiple fields change at once, they may trigger multiple disk writes. For performance, consider deferring saves or batching changes.

- this.apiUrl = apiUrl;
- save();
+ this.apiUrl = apiUrl;
// ...
// Save once at the end of configuration updates

Also applies to: 69-69, 84-84, 99-99, 114-114

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b5a1ac and 931601d.

📒 Files selected for processing (73)
  • .github/CODEOWNERS (1 hunks)
  • .gitignore (1 hunks)
  • .vscode/settings.json (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • Jenkinsfile (1 hunks)
  • README.md (1 hunks)
  • example.Jenkinsfile (1 hunks)
  • pom.xml (3 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStep.java (1 hunks)
  • src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java (0 hunks)
  • src/main/resources/index.jelly (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_de.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_es.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_fr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_it.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_pt_BR.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_sv.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_tr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_zh_CN.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_de.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_es.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_fr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_it.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_pt_BR.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_sv.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_tr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_zh_CN.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_de.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_es.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_fr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_it.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_pt_BR.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_sv.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_tr.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_zh_CN.html (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_de.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_es.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_fr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_it.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_pt_BR.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_sv.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_tr.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/ctrlplane/Messages_zh_CN.properties (1 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_de.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_es.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_it.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_pt_BR.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_sv.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_tr.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_zh_CN.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_de.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_de.html (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/Messages.properties (0 hunks)
  • src/main/resources/io/jenkins/plugins/sample/Messages_de.properties (0 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/sample/HelloWorldBuilderTest.java (0 hunks)
  • src/utils/CtrlplaneClient.groovy (0 hunks)
💤 Files with no reviewable changes (19)
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_de.html
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_de.html
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_it.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_pt_BR.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_tr.properties
  • src/main/resources/io/jenkins/plugins/sample/Messages_de.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_sv.properties
  • src/main/resources/io/jenkins/plugins/sample/Messages.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_zh_CN.properties
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_es.properties
  • src/utils/CtrlplaneClient.groovy
  • src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java
  • src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_de.properties
  • src/test/java/io/jenkins/plugins/sample/HelloWorldBuilderTest.java
🧰 Additional context used
🧠 Learnings (4)
src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey.html (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
🧬 Code Graph Analysis (2)
src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)
  • JobInfo (697-707)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (27-566)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)
  • Extension (24-170)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)
  • Extension (33-790)
🪛 LanguageTool
CONTRIBUTING.md

[grammar] ~10-~10: Probably a preposition is missing after ‘apply’.
Context: ...the existing code style. Consider using mvn spotless:apply verify to format your code. * Add unit ...

(ATD_VERBS_TO_COLLOCATION)


[uncategorized] ~11-~11: Possible missing comma found.
Context: ...unit tests for new functionality or bug fixes if applicable. 4. Test: Build the ...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~26-~26: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1581 characters long)
Context: ...issue. Thank you for your contributions!

(EN_EXCESSIVE_EXCLAMATION)

🪛 GitHub Check: Jenkins Security Scan
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java

[warning] 37-37: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java

[warning] 664-664: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java

[warning] 28-28: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey


[warning] 118-118: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckApiUrl connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST


[warning] 128-128: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckApiKey connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST


[warning] 138-138: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckAgentId connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST


[warning] 148-148: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckAgentWorkspaceId connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST


[warning] 164-164: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckPollingIntervalSeconds connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST

🔇 Additional comments (61)
.github/CODEOWNERS (1)

1-2: LGTM: Updated code ownership.

The code ownership has been properly assigned to individual GitHub users (@zacharyblasczyk and @jsbroks), replacing the previous team handle. This is in line with the PR's overall changes to restructure the Ctrlplane Jenkins plugin.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_sv.html (1)

1-4: LGTM: Swedish localization added correctly.

The Swedish help text for the API key field is properly formatted and provides clear instructions about what the API key is used for and where to find it.

.gitignore (2)

22-23: LGTM: Added .idea/ directory to .gitignore.

Correctly added the JetBrains IDE settings directory to prevent IDE-specific files from being tracked in the repository.


30-30: LGTM: Added work/ directory to .gitignore.

Correctly added the Jenkins work directory which contains runtime data that shouldn't be tracked in source control.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.properties (1)

1-11: LGTM: Well-structured English localization properties.

The English translations for the Ctrlplane configuration UI elements are clear, concise, and follow proper localization patterns. The descriptions provide good guidance for users setting up the integration.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_it.properties (1)

1-11: Italian localization file is accurate and complete.

The translations are appropriate and align with the plugin's configuration fields. No issues found.

README.md (1)

5-25: README content is clear, accurate, and user-friendly.

The updates provide essential information and correct links for users and contributors. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_fr.html (1)

1-3: French help text for API URL is clear and accurate.

The translation is correct and provides helpful guidance for users. No issues found.

Jenkinsfile (1)

6-12: Jenkinsfile formatting improvements are appropriate.

The changes enhance readability without affecting build logic. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_sv.html (1)

1-3: Swedish help text for API URL is clear and accurate.

The translation is correct and provides helpful guidance for users. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl.html (1)

1-3: Help text is clear and accurate.

The documentation provides concise and helpful guidance for users configuring the API URL.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_zh_CN.html (1)

1-3: Chinese help text is clear and accurate.

The translation matches the English version and provides clear guidance for users.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_tr.html (1)

1-3: Turkish help text is clear and accurate.

The translation matches the English version and provides clear guidance for users.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_es.html (1)

1-3: Spanish help text is clear and accurate.

The translation matches the English version and provides clear guidance for users.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_de.html (1)

1-4: German help text is clear and accurate.

The translation is correct and provides helpful guidance for users configuring the API key.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_de.properties (1)

1-2: German localization strings are accurate and well-formatted.

No issues found; the translations are clear and appropriate for the plugin context.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_it.properties (1)

1-2: Italian localization strings are correct and well-integrated.

No issues detected; the translations are suitable for the intended plugin usage.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_es.properties (1)

1-2: Spanish localization strings are accurate and appropriate.

No issues found; the translations are clear and contextually correct.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_pt_BR.html (1)

1-4: Brazilian Portuguese help content is clear and well-structured.

No issues found; the translation and HTML formatting are appropriate for Jenkins help documentation.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_sv.properties (1)

1-2: Swedish localization strings are accurate and well-formatted.

No issues detected; the translations are suitable for the plugin context.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_fr.properties (1)

1-2: French localization looks correct and clear.

The translations are accurate and contextually appropriate for the plugin's description and configuration instructions.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_pt_BR.html (1)

1-3: Brazilian Portuguese help text is clear and accurate.

The translation and HTML structure are correct for the API URL help text.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_it.html (1)

1-4: Italian help text for API key is clear and well-structured.

The translation is accurate and the instructions are user-friendly.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_it.html (1)

1-3: Italian help text for API URL is accurate and clear.

The translation and HTML structure are correct for the API URL help text.

.vscode/settings.json (1)

1-3: VSCode Java build configuration automation is correctly enabled.

This setting is standard and helps keep the Java environment in sync with project changes.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_fr.html (1)

1-4: French help file is clear and appropriate.

The localized help content is accurate and improves user experience for French-speaking users.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiUrl_de.html (1)

1-3: German help file is clear and contextually correct.

The localized help content is accurate and provides clear guidance for German-speaking users.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_tr.properties (1)

1-2: Turkish localization file is accurate and valuable.

The translations are correct and enhance the plugin's accessibility for Turkish-speaking users.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_de.properties (1)

1-11: German localization for configuration UI is complete and accurate.

The translations are correct and enhance the plugin's usability for German-speaking users.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey.html (1)

1-4: Verify API key storage method and update help text if needed.

Current help text instructs users to enter the API key directly. However, best practice (and retrieved learnings) indicate the plugin should use the Jenkins credentials plugin, referencing a credentialsId instead. If this is already implemented, update the help text to instruct users to select a credential rather than enter the API key directly.

Please confirm whether the plugin uses direct API key entry or credentialsId for secure storage. If credentialsId is used, update this help file accordingly.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_zh_CN.html (1)

1-4: Chinese help file is clear and well-structured.

The static help content is accurate, clear, and appropriately localized for Chinese users. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_es.html (1)

1-4: Spanish help file is clear and appropriate.

The static help content is accurate, clear, and well-localized for Spanish-speaking users. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_tr.properties (1)

1-11: Turkish localization file is complete and consistent.

All configuration fields are translated and the keys are consistent with other language files. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_fr.properties (1)

1-11: French localization file is complete and consistent.

All configuration fields are translated and the keys are consistent with other language files. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/help-apiKey_tr.html (1)

1-4: Turkish help file is clear and well-localized.

The static help content is accurate, clear, and well-localized for Turkish users. No issues found.

src/main/resources/index.jelly (1)

3-7: Localization and structure improved; previous grammar issue resolved.

The switch to localization keys for plugin description and configuration instructions is correct and resolves the previous grammatical fragment. The structure is clear and maintainable.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_zh_CN.properties (1)

1-11: Chinese localization is complete and accurate.

All required keys are present and translations are contextually appropriate for the configuration UI.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_pt_BR.properties (1)

1-2: Brazilian Portuguese localization is accurate and complete.

Both required keys are present and translations are contextually correct.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages_zh_CN.properties (1)

1-2: Chinese localization is accurate and complete.

Both required keys are present and translations are contextually correct.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_es.properties (1)

1-11: Spanish localization is complete and accurate.

All required keys are present and translations are contextually appropriate for the configuration UI.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_pt_BR.properties (1)

1-11: Brazilian Portuguese localization is complete and accurate.

All configuration fields are translated clearly and consistently. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/Messages.properties (1)

1-2: Plugin messages are clear and appropriate.

Descriptions are concise and accurately reflect the plugin's functionality.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config_sv.properties (1)

1-11: Swedish localization is complete and accurate.

All configuration fields are translated clearly and consistently. No issues found.

src/main/resources/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration/config.jelly (1)

1-26: Global configuration UI is complete and well-structured.

All required fields are present, use appropriate input types, and reference localized strings. No issues found.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java (2)

8-15: Good test class setup.

The test class follows best practices with proper initialization of the CtrlplaneJobPoller instance in the setUp method.


17-67: Comprehensive URL parsing test coverage.

These tests thoroughly validate the extractJobNameFromUrl method with various Jenkins URL formats including simple, nested, context-path, complex hierarchies, and URLs with query parameters. Edge cases like invalid, null, and blank URLs are also properly handled.

example.Jenkinsfile (2)

7-7: Parameter description update for clarity.

The JOB_ID parameter description has been updated to clearly indicate it's passed by the plugin, which improves usability.


11-36: Simplified job fetching with new pipeline step.

The implementation has been improved by:

  1. Using a clear stage name that reflects its purpose
  2. Replacing complex script loading with a direct pipeline step call
  3. Adding helpful JSON output of job details
  4. Including commented examples showing how to access fields from the job details

This simplification makes the pipeline easier to understand and maintain while providing good examples for users.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java (2)

12-16: Good test setup with JenkinsSessionRule.

Using JenkinsSessionRule is appropriate for testing configuration persistence across Jenkins restarts.


17-116: Thorough configuration UI and persistence testing.

This test method comprehensively validates:

  1. Default configuration values
  2. UI form interactions for all configuration fields
  3. Persistence of values after Jenkins restart

The test follows best practices by:

  • Checking default values first
  • Using appropriate HTML form elements for different field types
  • Verifying each field is correctly updated and persisted
  • Including descriptive assertions that clearly state what's being tested

This thorough approach ensures the global configuration is working as expected and resilient to restarts.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (3)

21-58: Effective test setup with mocking.

The test class is well-structured with:

  1. JenkinsRule for Jenkins environment simulation
  2. Mock JobAgent for isolated testing
  3. A testable subclass that exposes protected methods for testing
  4. Proper initialization in the setUp method

The approach of creating a testable subclass that overrides protected methods is a good pattern for testing classes with protected functionality.


70-89: Good job status update testing.

The test effectively verifies that the job status update correctly passes expected parameters to the JobAgent. The use of Mockito's eq() method ensures precise parameter matching.


91-129: Comprehensive job info extraction tests.

These tests thoroughly validate the job info extraction logic, including:

  1. Proper extraction of job details from configuration maps
  2. Correct handling of job status filtering (skipping non-pending jobs)

The tests use appropriate assertions to verify all aspects of the extracted JobInfo.

src/main/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStep.java (1)

33-42: Good constructor validation.

Your constructor properly validates the jobId parameter, ensuring it is neither null nor empty and is a valid UUID. This robust approach avoids runtime surprises.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (4)

56-61: Great defensive check for Jenkins termination.

It’s good practice to skip the polling cycle when Jenkins is terminating. This avoids unnecessary API calls and potential partial operations.


74-74: Reconciliation step is valuable.

Explicitly reconciling in-progress jobs after a restart or unexpected downtime is a robust approach to ensure Ctrlplane is kept updated with correct job statuses.


357-364: Status update before invoking Jenkins builds.

Updating Ctrlplane status to "in_progress" before actually scheduling the Jenkins job can lead to consistency gaps if the scheduling fails. Your follow-up warning log partially mitigates this, but be aware that Ctrlplane might show "in_progress" for a job that never got queued if something breaks right after.


497-502: Tracking queue item with ActiveJobInfo.

Storing queue ID and job URL in ActiveJobInfo is a neat approach for re-checking progress later. This pattern helps unify queued vs. running states in one data structure.

pom.xml (3)

8-8: Upgraded parent plugin to version 5.9.

This ensures access to newer Jenkins plugin features and fixes. Verify compatibility with your chosen Jenkins baseline if any cross-dependency constraints apply.


17-37: Updated plugin name and added developers.

Adding accurate naming and developer details is good for clarity and maintainability. This helps users identify the plugin in the update center and fosters collaboration.


48-60: Changed Jenkins baseline & BOM coordinates.

Setting <jenkins.baseline>2.492</jenkins.baseline> and referencing its BOM ensures alignment with that version’s API. Confirm all plugin dependencies remain compatible with this new baseline.

private final ConcurrentHashMap<String, ActiveJobInfo> activeJenkinsJobs = new ConcurrentHashMap<>();
private JobAgent jobAgent;
private String lastApiUrl;
private String lastApiKey;

Check warning

Code scanning / Jenkins Security Scan

Jenkins: Plaintext password storage Warning

Field should be reviewed whether it stores a password and is serialized to disk: lastApiKey
/** Configuration details for the poller. */
private static class CtrlplaneConfig {
final String apiUrl;
final String apiKey;

Check warning

Code scanning / Jenkins Security Scan

Jenkins: Plaintext password storage Warning

Field should be reviewed whether it stores a password and is serialized to disk: apiKey
Copy link
Contributor

@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: 1

♻️ Duplicate comments (4)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (2)

29-29: 🛠️ Refactor suggestion

Store the API key more securely.
Storing the apiKey field in plain text can expose sensitive credentials. Consider integrating with the Jenkins credentials plugin to store and retrieve tokens securely.

- private String apiKey;
+ private String credentialsId;
🧰 Tools
🪛 GitHub Check: Jenkins Security Scan

[warning] 29-29: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey


195-209: 🛠️ Refactor suggestion

Add @post annotation to protect doCheckAgentWorkspaceId.
To avoid potential CSRF vulnerabilities, this method should also be annotated with @POST (or @RequirePOST), in line with the other doCheck methods.

+ @POST
 public FormValidation doCheckAgentWorkspaceId(@QueryParameter String value) {
🧰 Tools
🪛 GitHub Check: Jenkins Security Scan

[warning] 195-195: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckAgentWorkspaceId connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)

159-159: Credentials usage reminder (same comment as before).
Retrieving a plaintext apiKey from global config repeats the earlier concern about secure credential storage. Integrate with the Jenkins credentials plugin instead.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

723-724: ⚠️ Potential issue

Use Jenkins credentials rather than storing the apiKey in plaintext.

The apiKey field in CtrlplaneConfig can expose secrets in logs or when serialized. Migrate to Jenkins credentials plugin by storing a credentialsId, then fetching the token via CredentialsProvider at runtime for best security practices:

- final String apiKey;
+ final String credentialsId;
🧰 Tools
🪛 GitHub Check: Jenkins Security Scan

[warning] 724-724: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 931601d and 28c7565.

📒 Files selected for processing (10)
  • CONTRIBUTING.md (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1 hunks)
  • src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneConfigChangeTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobProcessingTest.java (1 hunks)
  • src/test/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStepTest.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfigurationTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerTest.java
  • src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPollerMockTest.java
🧰 Additional context used
🧠 Learnings (2)
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (2)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store the API key. This involves replacing the direct apiKey field with a credentialsId field and using CredentialsProvider to look up the actual secret at runtime.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/jenkins-plugin#3
File: src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java:30-34
Timestamp: 2025-04-12T07:15:40.137Z
Learning: The Ctrlplane plugin should use the Jenkins credentials plugin to securely store API keys. This involves replacing the direct apiKey field with a credentialsId reference and using the credentials API to look up the actual secret at runtime.
🧬 Code Graph Analysis (1)
src/test/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStepTest.java (1)
src/main/java/io/jenkins/plugins/ctrlplane/api/JobAgent.java (1)
  • JobAgent (27-566)
🪛 GitHub Check: Jenkins Security Scan
src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java

[warning] 40-40: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: lastApiKey


[warning] 724-724: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java

[warning] 29-29: Jenkins: Plaintext password storage
Field should be reviewed whether it stores a password and is serialized to disk: apiKey


[warning] 195-195: Stapler: Missing POST/RequirePOST annotation
Potential CSRF vulnerability: If CtrlplaneGlobalConfiguration#doCheckAgentWorkspaceId connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @post or @RequirePOST

🪛 LanguageTool
CONTRIBUTING.md

[style] ~26-~26: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1616 characters long)
Context: ...issue. Thank you for your contributions!

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (8)
CONTRIBUTING.md (2)

1-25: Great contribution guidelines!
These instructions clearly outline the workflow for new contributors and emphasize code style checks with Spotless. No further issues spotted.


26-26: Possible false positive from style checker.
The static analysis flagged the usage of exclamation marks. However, there is only one exclamation mark here, which seems acceptable.

🧰 Tools
🪛 LanguageTool

[style] ~26-~26: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1616 characters long)
Context: ...issue. Thank you for your contributions!

(EN_EXCESSIVE_EXCLAMATION)

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneGlobalConfiguration.java (1)

125-134: Use of @post annotation here is commendable.
The @POST annotation for doCheckApiUrl helps prevent CSRF vulnerabilities and ensures that form validations requiring user input are protected. No concerns here.

src/test/java/io/jenkins/plugins/ctrlplane/steps/CtrlplaneGetJobStepTest.java (1)

1-123: Extensive test coverage.
The test class comprehensively verifies UUID validation, parameter handling, logging, step execution, global config access, and agent creation. No issues found.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobCompletionListener.java (1)

59-73: Status mapping logic is clear.
Mapping Jenkins build results (SUCCESS, UNSTABLE, FAILURE, ABORTED) to Ctrlplane statuses is handled well, ensuring consistent updates.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobProcessingTest.java (1)

1-210: Well-structured tests and coverage.

All test methods effectively validate core behaviors of job extraction, status updates, and handling of completed jobs. The setup of mock runs and verification of status updates is thorough. No major concerns found here.

src/main/java/io/jenkins/plugins/ctrlplane/CtrlplaneJobPoller.java (1)

232-267:

✅ Verification successful

Verify iterator removal usage on ConcurrentHashMap.

The method reconcileInProgressJobs calls iterator.remove() while iterating over a ConcurrentHashMap’s entrySet. Although Java’s ConcurrentHashMap provides weakly consistent iteration, confirm that calling remove() on the active iterator is supported and behaves reliably across all targeted Java versions.


🌐 Web query:

Does Java’s ConcurrentHashMap entrySet iterator reliably support the iterator.remove() operation in Java 8 or 11?

💡 Result:

In Java 8 and Java 11, the iterator of ConcurrentHashMap's entrySet supports the iterator.remove() operation reliably under certain conditions, but with caveats tied to its weakly consistent nature.

  1. Support for iterator.remove(): The ConcurrentHashMap entrySet and its iterators allow for safe removal of elements using iterator.remove(). This operation is thread-safe and does not throw ConcurrentModificationException, as the map is designed for concurrent modifications[1][6].

  2. Weakly Consistent Iterators: The iterators of ConcurrentHashMap are weakly consistent. This means they reflect the state of the map at some point during or after the creation of the iterator but do not guarantee real-time updates. Changes made directly to the map (e.g., adding or removing entries) while iterating will not necessarily be visible to the iterator, and such changes may affect whether iterator.remove() works as expected. Specifically, if an entry is modified or removed directly from the map (not via the iterator), calling iterator.remove() can lead to undefined behavior because the "last element returned" by the iterator may no longer exist[1][3][7].

  3. Behavior When Entries Are Modified During Iteration: If you update a mapping in the map after retrieving it via the iterator (map.put(key, newValue)), calling iterator.remove() might fail to remove the updated entry. This is because the mapping no longer matches the state the iterator is tracking, as was highlighted in some reported issues[7].

Summary

iterator.remove() on ConcurrentHashMap's entrySet works reliably if:

  • The map is modified only through the iterator during iteration (e.g., using iterator.remove()).
  • No external modifications (like map.put() or map.remove()) affect the entry being processed by the iterator.

Therefore, while the feature is supported, care must be taken to avoid conflicting modifications that can lead to unexpected behavior.

Citations:


Iterator removal usage verified as safe for this scenario.

After reviewing the web query results, using iterator.remove() on the ConcurrentHashMap’s entrySet iterator in Java 8 and Java 11 is supported and behaves reliably—as long as the removal is performed solely via the iterator and not concurrently modified in other ways. In this code, all removals occur through the iterator, so the usage is appropriate.

No changes are required here.

src/test/java/io/jenkins/plugins/ctrlplane/CtrlplaneConfigChangeTest.java (1)

1-184: Good coverage of configuration change scenarios.

The test ensures that altered fields (API URL, API key, agent name, workspace, polling interval) correctly trigger re-initialization of the job agent. The default agent name fallback is also well tested.

@zacharyblasczyk zacharyblasczyk merged commit b2243bd into main Apr 15, 2025
3 checks passed
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.

2 participants