ZDDC/zddc/internal/listing/listing_test.go
ZDDC cb46c2ef8c feat(zddc-server): user profile page replaces /.admin/
Replaces the super-admin-only /.admin/ surface with a public-by-default
/.profile/ page that layers admin tools server-side based on the
caller's effective access:

- Universal (everyone, anonymous included): identity card, effective
  access summary, theme picker, localStorage utilities (export / import
  / clear, landing-presets viewer).
- Subtree admins additionally see: editable .zddc files list (linking
  to the existing form-based editor) and a "Create new project folder"
  form.
- Super-admins additionally see: server config, log viewer, whoami
  headers (the old /.admin/ JSON endpoints, repointed under /.profile/).

Project creation is gated on CanEditZddc(newDir) — the same strict-
ancestor rule that already governs .zddc writes — so no new authority
concept is introduced. ValidateProjectName mirrors the existing
reserved-prefix policy (no leading '.' or '_', no path separators).

/.admin/* is hard-cut: no redirect shim. Old URLs fall through to the
existing dot-prefix guard and 404. Custom CSS file rename: prefer
<root>/.profile.css, fall back to legacy <root>/.admin.css.

Per-resource 404 leakage gates preserved on whoami / config / logs /
zddc / projects so non-admin callers cannot detect the existence of
admin-only sub-resources.

Tree-wide gofmt -w applied as a side-effect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:32:02 -05:00

60 lines
1.4 KiB
Go

package listing
import (
"os"
"path/filepath"
"testing"
)
// TestFromDirEntriesFiltersHidden asserts that both '.' and '_' prefixed
// entries are excluded from listings — the '.' branch is the long-standing
// rule (matches dispatch dot-prefix guard); '_' is for operator-managed
// scaffolding like install.zip's _template/ that should be reachable by
// direct URL but invisible to browse.
func TestFromDirEntriesFiltersHidden(t *testing.T) {
dir := t.TempDir()
for _, name := range []string{
"Project-A",
"Project-B",
".zddc", // hidden file
".devshell", // hidden dir
"_template", // scaffolding dir
"_archive", // scaffolding dir
"_notes.txt", // scaffolding file
"normal.txt",
} {
path := filepath.Join(dir, name)
if err := os.WriteFile(path, []byte("x"), 0o644); err != nil {
t.Fatalf("write %s: %v", name, err)
}
}
entries, err := os.ReadDir(dir)
if err != nil {
t.Fatalf("ReadDir: %v", err)
}
got, err := FromDirEntries(entries, "/")
if err != nil {
t.Fatalf("FromDirEntries: %v", err)
}
want := map[string]bool{
"Project-A": true,
"Project-B": true,
"normal.txt": true,
}
if len(got) != len(want) {
var names []string
for _, e := range got {
names = append(names, e.Name)
}
t.Fatalf("got %d entries (%v), want %d (%v)", len(got), names, len(want), want)
}
for _, e := range got {
if !want[e.Name] {
t.Errorf("unexpected entry in listing: %q", e.Name)
}
}
}