Skip to content

Make expiration of URLs configurable#783

Draft
daniel-beck wants to merge 1 commit intojenkinsci:masterfrom
daniel-beck:configurable-presigned-url-duration
Draft

Make expiration of URLs configurable#783
daniel-beck wants to merge 1 commit intojenkinsci:masterfrom
daniel-beck:configurable-presigned-url-duration

Conversation

@daniel-beck
Copy link
Member

@daniel-beck daniel-beck commented Mar 10, 2026

We got a report from someone who wanted to reduce the pre-signed URL validity period from the default of 1 hr.

This PR implements that as a pair of system properties:

  • io.jenkins.plugins.artifact_manager_jclouds.JCloudsVirtualFile.EXPIRATION_SECONDS is the validity of the pre-signed URL that a user is redirected to when accessing an artifact, in seconds. The default is reduced from 1 hr to 1 minute. If set to 0, the plugin will not generate a pre-signed URL, and the links won't work for anyone accessing them directly (unless the bucket is public I guess).
  • io.jenkins.plugins.artifact_manager_jclouds.BlobStoreProvider.DEFAULT_DURATION_SECONDS is the validity of the pre-signed external URL for archive, stash, and unstash operations, in seconds. This remains 1 hr by default. This addition will also allow users for whom 1 hr of archiving isn't enough to tune the expiration of that to be longer.

This is for your consideration. Test coverage (actual, e.g., minio-based coverage so far is pretty minimal, so a bit more effort) and docs will follow if accepted in principle.

Testing done

Manual so far, with a local Minio server and script console System.setProperty('io.jenkins.plugins.artifact_manager_jclouds.JCloudsVirtualFile.EXPIRATION_SECONDS', '…'):
Locally set expiration to 0 and got redirected to an XML AccessDenied error page.
Locally set expiration to 5, downloaded an artifact, reloaded the URL a few seconds later and got AccessDenied.

Please note that locally for hpi:run I needed

diff --git a/pom.xml b/pom.xml
index 5c76f80..8bf439d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,7 @@
     <spotbugs.effort>Max</spotbugs.effort>
     <spotbugs.threshold>Low</spotbugs.threshold>
     <hpi.strictBundledArtifacts>true</hpi.strictBundledArtifacts>
+    <hpi-plugin.version>3.1814.v77d15159f9b_d</hpi-plugin.version>
     <hpi.bundledArtifacts>aws-s3,guice-assistedinject,jakarta.ws.rs-api,jclouds-blobstore,jclouds-core,s3,sts,tika-core</hpi.bundledArtifacts>
   </properties>

because the current parent pom doesn't resolve transitive dependencies correctly.

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests that demonstrate the feature works or the issue is fixed

Comment on lines +264 to +266
if (expiration.isZero()) {
return blob.getMetadata().getUri().toURL();
}
Copy link
Member

Choose a reason for hiding this comment

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

#660 / #781 I guess? I would rather not include this here as it does not seem necessary and would require dedicated testing with a public bucket.

@NonNull
public abstract URL toExternalURL(@NonNull Blob blob, @NonNull HttpMethod httpMethod) throws IOException;
public URL toExternalURL(@NonNull Blob blob, @NonNull HttpMethod httpMethod) throws IOException {
return toExternalURL(blob, httpMethod, Duration.ofSeconds(SystemProperties.getInteger(BlobStoreProvider.class.getName() + ".DEFAULT_DURATION_SECONDS", 3600)));
Copy link
Member

Choose a reason for hiding this comment

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

Use SystemProperties.getDuration.

@Override
public URL toExternalURL() throws IOException {
return provider.toExternalURL(getBlob(), HttpMethod.GET);
return provider.toExternalURL(getBlob(), HttpMethod.GET, Duration.ofSeconds(SystemProperties.getInteger(JCloudsVirtualFile.class.getName() + ".EXPIRATION_SECONDS", 60)));
Copy link
Member

Choose a reason for hiding this comment

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

ditto

blob.getMetadata().setContainer(this.getContainer());
blob.getMetadata().getContentMetadata().setContentType(contentTypes.get(entry.getValue()));
artifactUrls.put(entry.getValue(), this.toExternalURL(blob, HttpMethod.PUT, s3Presigner));
artifactUrls.put(entry.getValue(), this.toExternalURL(blob, HttpMethod.PUT, s3Presigner, Duration.ofHours(1)));
Copy link
Member

@jglick jglick Mar 10, 2026

Choose a reason for hiding this comment

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

What is this duration? Why is it not configurable?

*/
@NonNull
public abstract URL toExternalURL(@NonNull Blob blob, @NonNull HttpMethod httpMethod) throws IOException;
public URL toExternalURL(@NonNull Blob blob, @NonNull HttpMethod httpMethod) throws IOException {
Copy link
Member

Choose a reason for hiding this comment

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

Not implemented externally, no need to offer a compat layer.

@jglick jglick added the enhancement New feature or request label Mar 10, 2026
@daniel-beck daniel-beck self-assigned this Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants