feat(backend): report repository visibility in the root listing - #14
Merged
Conversation
The dashboard overview lists repositories with nothing but a name, so it cannot tell a public repository from a hidden or private one. The value is known at runtime but never left the backend. Entries of the root listing are now RepositoryDirectoryInfo and carry a visibility field. Every other directory keeps using SimpleDirectoryInfo, which has no visibility to report. The field is additive: name and type are unchanged, so clients written against the previous payload keep working. Nothing is leaked. Repositories the caller cannot access are dropped by RepositorySecurityProvider.canAccessRepository before the response is assembled, so an anonymous caller only ever learns that public repositories are public. Signed-off-by: TheMeinerLP <github@themeinerlp.dev>
TheMeinerLP
force-pushed
the
feat/repository-visibility-in-listing
branch
from
August 8, 2026 21:56
ec12904 to
32bda6f
Compare
Test results 69 files 69 suites 8m 48s ⏱️ Results for commit 32bda6f. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The dashboard overview lists repositories as rows carrying nothing but a name, so it cannot show whether a repository is public, hidden or private. The value exists on
Repositoryat runtime but reached no endpoint.Entries of the root listing (
GET /api/maven/details, the variant without a{repository}path parameter) are now a newRepositoryDirectoryInfoand carry avisibilityfield.Before:
{ "name": "/", "files": [ { "name": "releases", "type": "DIRECTORY" }, { "name": "snapshots", "type": "DIRECTORY" } ], "type": "DIRECTORY" }After:
{ "name": "/", "files": [ { "name": "releases", "visibility": "PUBLIC", "type": "DIRECTORY" }, { "name": "snapshots", "visibility": "PUBLIC", "type": "DIRECTORY" } ], "type": "DIRECTORY" }Design notes
SimpleDirectoryInfois used for every directory listing, not just the repository root, and it is a public type incom.reposilite.storage.apithat plugins construct. It is left untouched, so no folder inside a repository grows a meaningless visibility.com.reposilite.storage.apibecause direct subclasses of the sealedFileDetailshave to be declared in the same package and module. That is the reason a repository concept sits next to the storage ones, and the class carries a comment saying so.nameandtypeare untouched, nothing was renamed, removed or retyped, and a client that ignores the new field keeps working.MavenFacade.findRepositorieskeeps itsDirectoryInforeturn type, so plugins compile unchanged.reposilite-site/data/guides/developers/endpoints.mdwas extended to match.Security
Emitting the visibility leaks nothing, and this was checked against
RepositorySecurityProviderrather than assumed:canAccessRepositoryreturnstrueforPUBLIC, and forHIDDENandPRIVATEonly whenaccessTokenFacade.canSee(token, "/<repository>")holds. An absent token fails both.RepositoryService.getRootDirectoryapplies that filter before mapping to the response, so a repository the caller cannot access never becomes an entry in the first place. It is the only path that builds this listing.A regression test asserts the negative case as well: a token scoped to
/releasessees neither the hidden nor the private repository.Type of change
feat- new featureHow was this tested?
./gradlew buildpasses, including:reposilite-backend:testand:reposilite-backend:integration.MavenFacadeTest.should describe the visibility of every listed repository: an anonymous caller gets public repositories only, each withPUBLIC; a manager token additionally gets the hidden and private ones with their own value.RepositoryVisibilityIntegrationTest(new, boots a real instance and reads the actual JSON):name,type,files) is unchanged,Checklist
CLAUDE.md./gradlew buildpasses locallyOut of scope, found on the way
StorageProvider.usage()was confirmed broken while reading this code, and it deserves its own issue rather than a fix here.FileSystemStorageProvider.usage()isgetFileSize(Location.empty()), andgetFileSizereturns-1for a directory, so it always reports-1.FixedQuota.canHoldthen computesmaxSize - (-1)andPercentageQuota.canHoldcomputesmax - (-1), meaning neither quota ever accounts for what is already stored: they only reject a single upload larger than the whole limit.S3StorageProvider.usage()returnsok(-1)too, but it overridescanHoldwithLong.MAX_VALUE, so S3 has no quota at all.