generated from coulomb/repo-seed
feat: implement T09, T15, T21 — userinfo endpoint, LLDAP export, negative tests
- T09: /userinfo with RS256 JWT validation, scope-filtered claims - T15: LLDAP→canonical export tool with validation, migration_event telemetry - T21: Negative test suite (Scenario D) — all 7 unsupported features verified All go tests passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,11 +3,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"keycape/internal/adapters/lldap"
|
||||
"keycape/internal/migration/lldapexport"
|
||||
"keycape/internal/server/telemetry"
|
||||
"keycape/internal/validator"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Fprintln(os.Stderr, "lldap-export: not yet implemented (T06+)")
|
||||
os.Exit(1)
|
||||
// Flags.
|
||||
url := flag.String("url", "ldap://localhost:389", "LLDAP server URL (ldap:// or ldaps://)")
|
||||
bindDN := flag.String("bind-dn", "", "Service account bind DN (required)")
|
||||
bindPW := flag.String("bind-pw", "", "Service account password (required)")
|
||||
baseDN := flag.String("base-dn", "", "LDAP search base DN (required)")
|
||||
output := flag.String("output", "canonical-export.yaml", "Output file path")
|
||||
tlsSkip := flag.Bool("tls-skip-verify", false, "Skip TLS certificate verification (dev only)")
|
||||
flag.Parse()
|
||||
|
||||
if *bindDN == "" || *baseDN == "" {
|
||||
fmt.Fprintln(os.Stderr, "lldap-export: --bind-dn and --base-dn are required")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log := zerolog.New(os.Stderr).With().Timestamp().Logger()
|
||||
emitter := telemetry.NewLogEmitter(log)
|
||||
|
||||
cfg := lldap.Config{
|
||||
URL: *url,
|
||||
BindDN: *bindDN,
|
||||
BindPW: *bindPW,
|
||||
BaseDN: *baseDN,
|
||||
TLSSkipVerify: *tlsSkip,
|
||||
}
|
||||
|
||||
repo := lldap.New(cfg)
|
||||
exp := lldapexport.New(repo, validator.ModeProvisioning, emitter)
|
||||
|
||||
result, err := exp.Export(context.Background(), *output)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "lldap-export: export failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stdout, "Exported %d users, %d groups to %s\n",
|
||||
len(result.Users), len(result.Groups), *output)
|
||||
|
||||
if len(result.IncompatibilityReport) > 0 {
|
||||
fmt.Fprintln(os.Stderr, "Incompatibility report:")
|
||||
for _, item := range result.IncompatibilityReport {
|
||||
fmt.Fprintln(os.Stderr, " -", item)
|
||||
}
|
||||
os.Exit(2) // partial success: exported with warnings
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user