Codevault initial commit

This commit is contained in:
2026-08-16 16:23:14 +03:00
commit 6ee80f1c8f
47 changed files with 3177 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
package runcmd
import (
"context"
"fmt"
"github.com/kanootoko/codevault/internal/auth"
"github.com/kanootoko/codevault/internal/db"
)
// AddUser opens (creating if necessary) the database at dbPath and upserts a
// user with the given login/password. It intentionally does not depend on the
// application config.
func AddUser(dbPath, login, password string) error {
database, err := db.Open(dbPath)
if err != nil {
return fmt.Errorf("error on opening database: %w", err)
}
defer func() { _ = database.Close() }()
hash, err := auth.Hash(login, password)
if err != nil {
return fmt.Errorf("error on hashing password: %w", err)
}
users := db.NewUsersRepository(database)
if err := users.Upsert(context.Background(), login, hash); err != nil {
return fmt.Errorf("error on upserting user: %w", err)
}
return nil
}

View File

@@ -0,0 +1,59 @@
package runcmd
import (
"bytes"
"fmt"
"os"
"time"
"gopkg.in/yaml.v3"
"github.com/kanootoko/codevault/internal/config"
)
func ConfigExample(configPath string) error {
configExample := config.Config{
Environment: config.DevelopmentEnvironment,
Server: config.ServerConfig{
Address: ":8080",
// Example: a Docker-network CIDR in front of a reverse proxy nginx.
// Replace with the actual proxy's IP/CIDR, or leave empty to trust
// no forwarded-for headers.
TrustedProxies: []string{"172.16.0.0/12"},
},
Database: config.DatabaseConfig{
Path: "./codevault.db",
},
RateLimit: config.RateLimitConfig{
MaxFailures: 10,
Window: time.Minute,
},
Observability: config.ObservabilityConfig{
Logging: config.LoggingConfig{
Stderr: config.InfoLoggingLevel,
Files: map[config.LoggingLevel]string{config.InfoLoggingLevel: "./info.log"},
Exporter: config.LogsExporterConfig{
Level: config.InfoLoggingLevel,
Endpoint: "http://127.0.0.1:4317/v1/logs",
Transport: "grpc",
},
},
Metrics: config.MetricsConfig{
Host: "127.0.0.1",
Port: 9092,
},
},
}
configBytesBuffer := bytes.NewBuffer(nil)
encoder := yaml.NewEncoder(configBytesBuffer)
encoder.SetIndent(2)
err := encoder.Encode(configExample)
if err != nil {
return fmt.Errorf("cannot marshal example config: %w", err)
}
err = os.WriteFile(configPath, configBytesBuffer.Bytes(), os.ModePerm)
if err != nil {
return fmt.Errorf("cannot write config file: %w", err)
}
return nil
}

54
internal/runcmd/run.go Normal file
View File

@@ -0,0 +1,54 @@
package runcmd
import (
"context"
"fmt"
"go.uber.org/zap"
"github.com/kanootoko/codevault/internal/config"
"github.com/kanootoko/codevault/internal/db"
"github.com/kanootoko/codevault/internal/httpserver"
"github.com/kanootoko/codevault/internal/observability/logging"
"github.com/kanootoko/codevault/internal/observability/metrics"
"github.com/kanootoko/codevault/internal/ratelimit"
"github.com/kanootoko/codevault/internal/utils/gshutdown"
)
func RunServer(ctx context.Context, appConfig config.Config) error {
logger, err := logging.LoggerFromCtx(ctx)
if err != nil {
return fmt.Errorf("error on getting logger: %w", err)
}
appMetrics := metrics.NewMetrics(metrics.GetMeter())
database, err := db.Open(appConfig.Database.Path)
if err != nil {
return fmt.Errorf("error on opening database: %w", err)
}
_ = gshutdown.SubtaskStarted(ctx, "database")
go func() {
defer func() { _ = gshutdown.SubtaskFinished(ctx, "database") }()
<-ctx.Done()
if err := database.Close(); err != nil {
logger.Error("error on closing database", zap.Error(err))
}
}()
secrets := db.NewSecretsRepository(database)
users := db.NewUsersRepository(database)
limiter := ratelimit.NewLimiter(appConfig.RateLimit.MaxFailures, appConfig.RateLimit.Window)
router, err := httpserver.New(secrets, users, limiter, appMetrics, appConfig.Server.TrustedProxies)
if err != nil {
return fmt.Errorf("error on building http router: %w", err)
}
logger.Info("starting codevault server")
if err := httpserver.Run(ctx, appConfig.Server.Address, router, limiter); err != nil {
return fmt.Errorf("error on running http server: %w", err)
}
return nil
}