cloudzilla Commits 96a6f51

feat(security): private-repo visibility + transport + UI polish (#29)

Repositories can now be marked private. Anonymous reads of a private repository return 404 on the web UI and on both
git transports, so its existence is not revealed.

Adds an is_private column with an index, and tightens the visibility check in RepoService.Get.
MK Malith Kuruppu <malith@example.com> 96a6f51c3e0b8d47a2f19e5c7b4d6a80f3e12c95
Parents: 7e1d4b9

Checks

Success: ci/build — Build passed in 1m 42s Details
Success: ci/test — 412 tests passed Details
Failure: ci/lint — 2 issues found Details
3 files changed, +8 −2
internal/service/repo_service.go
+4 -1
@@ -18,7 +18,10 @@ func (s *RepoService) Get(ctx context.Context, owner, name string) (*model.Repository, error) {
18 18 repo, err := s.stores.Repos.GetByOwnerAndName(ctx, owner, name)
19 19 if err != nil {
20 20 return nil, err
21 21 }
22 - return repo, nil
22 + if repo.IsPrivate && !s.canRead(ctx, repo) {
23 + return nil, ErrNotFound
24 + }
25 + return repo, nil
23 26 }
24 27
25 28 func (s *RepoService) List(ctx context.Context, owner string) ([]model.Repository, error) {
internal/db/migrations/0042_repo_visibility.sql
+2 -1
@@ -1,4 +1,5 @@
1 1 -- 0042_repo_visibility.sql
2 - ALTER TABLE repositories ADD COLUMN visibility TEXT;
2 + ALTER TABLE repositories ADD COLUMN is_private BOOLEAN NOT NULL DEFAULT FALSE;
3 + CREATE INDEX idx_repositories_is_private ON repositories (is_private);
3 4
docs/git-transport.md
+2 -0
@@ -41,3 +41,5 @@ Clone over HTTP or SSH.
41 41
42 42 Private repositories require authentication on both transports.
43 +
44 + Anonymous requests to a private repository return `404`, not `403`.