diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml deleted file mode 100644 index 4543ee2284951e92c1cc23a1ef000375b5a4c735..0000000000000000000000000000000000000000 --- a/.github/workflows/cd.yml +++ /dev/null @@ -1,182 +0,0 @@ -name: CD - -on: - push: - branches: - - main - pull_request: - - -jobs: - cd: - strategy: - matrix: - go-version: [~1.17] - runs-on: ubuntu-latest - env: - GO111MODULE: "on" - CONTAINER_REPO: "ghcr.io/${{ github.repository }}" - ENVIRONMENT: development - AWS_DEFAULT_REGION: us-east-1 - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - SOFT_SERVE_REPO_KEYS: "${{ secrets.SOFT_SERVE_REPO_KEYS }}" - - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - # Remove this later - - name: Clone internal repositories - run: | - git clone -b release https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/charm-internal ../charm - git clone -b master https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/bubbletea-internal ../bubbletea - git clone -b master https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/wish ../wish - - - name: Login to GitHub Container Registry - uses: docker/login-action@v1 - if: github.event_name == 'push' - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build Docker images using GoReleaser - uses: goreleaser/goreleaser-action@master - if: github.event_name == 'push' - with: - version: latest - # https://github.com/goreleaser/goreleaser/discussions/1534 - args: -f .goreleaser.yml --snapshot - - # Must add GH Actions write access - # https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions - - name: Push Docker images - if: github.event_name == 'push' - run: | - docker push $CONTAINER_REPO:snapshot - docker push $CONTAINER_REPO:$GITHUB_SHA-snapshot - - - name: Setup Terraform - uses: hashicorp/setup-terraform@v1 - with: - # terraform_version: 0.13.0 - cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }} - - - name: Terraform Variables - id: tfvars - run: | - cat <live.auto.tfvars - environment = "$ENVIRONMENT" - aws_region = "$AWS_DEFAULT_REGION" - app_image = "$CONTAINER_REPO:$GITHUB_SHA-snapshot" - authorization_keys = <Show Plan - - \`\`\`\n - ${process.env.PLAN} - \`\`\` - - - - *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`; - - if (process.env.COMMENT_ID) { - github.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: output - }) - } else { - github.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: output - }) - } - - - name: Terraform Plan Status - if: steps.plan.outcome == 'failure' - run: exit 1 - - - - name: Terraform Apply - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - run: terraform apply -auto-approve ${{ steps.tfvars.outputs.vars }} - - - slack-workflow-status: - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - name: Post Workflow Status To Slack - needs: - - cd - runs-on: ubuntu-latest - steps: - - name: Slack Workflow Notification - uses: Gamesight/slack-workflow-status@master - with: - # Required Input - repo_token: ${{ secrets.GITHUB_TOKEN }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - # Optional Input - channel: '#devops' - name: "${{ github.repository }} 🥤 workflow" - icon_emoji: ':cup_with_straw:' - icon_url: 'https://avatars.githubusercontent.com/u/57376114?s=200&v=4' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 3b17b83d7ab869ff6c63a500ebfbe8c93c217aa9..0000000000000000000000000000000000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - pull_request: - -jobs: - - build: - strategy: - matrix: - go-version: [~1.17] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - # Remove this later - - name: Clone internal repositories - run: | - git clone -b release https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/charm-internal ../charm - git clone -b master https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/bubbletea-internal ../bubbletea - git clone -b master https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/wish ../wish - - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - - name: Build - run: go build -v ./... - - - name: Test - run: go test -v ./... diff --git a/.github/workflows/soft-serve.yml b/.github/workflows/soft-serve.yml deleted file mode 100644 index 311bb63f478aaeb2b7b0d93f3da03d7da35a34a2..0000000000000000000000000000000000000000 --- a/.github/workflows/soft-serve.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Soft-Serve - -on: - push: - branches: - - main - -jobs: - softserve: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Push to Soft-Serve - uses: charmbracelet/soft-serve-action@v1 - with: - server: "beta.charm.sh" - ssh-key: "${{ secrets.CHARM_SOFT_SERVE_KEY }}" - name: "soft-serve" \ No newline at end of file diff --git a/.gitignore b/.gitignore index afadd7767fc59b5be7cf7e842c28ebc8535e4d76..343b19865854d6c96f2dff68a316a7498c90922b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ -soft-serve -.ssh -.repos -dist -.terraform* -*.tfstate* -*auto.tfvars \ No newline at end of file +cmd/soft/soft +cmd/soft/.ssh +cmd/soft/.repos diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 447d7c4cdb52e0b47f0a7dcdc6dfb050900f1fed..0000000000000000000000000000000000000000 --- a/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM alpine:latest - -RUN apk update && apk add --update nfs-utils git && rm -rf /var/cache/apk/* - -COPY soft-serve /usr/local/bin/soft-serve - -# Create directories -WORKDIR /soft-serve -# Expose data volume -VOLUME /soft-serve - -# Environment variables -ENV SOFT_SERVE_KEY_PATH "/soft-serve/ssh/soft_serve_server_ed25519" -ENV SOFT_SERVE_REPO_KEYS "" -ENV SOFT_SERVE_REPO_KEYS_PATH "/soft-serve/ssh/soft_serve_git_authorized_keys" -ENV SOFT_SERVE_REPO_PATH "/soft-serve/repos" - -# Expose ports -# SSH -EXPOSE 23231/tcp - -# Set the default command -ENTRYPOINT [ "/usr/local/bin/soft-serve" ] \ No newline at end of file diff --git a/cmd/soft/main.go b/cmd/soft/main.go new file mode 100644 index 0000000000000000000000000000000000000000..49fbd734be7a36b347ff4eb380423f1112292920 --- /dev/null +++ b/cmd/soft/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "log" + + "github.com/charmbracelet/soft" + + "github.com/meowgorithm/babyenv" +) + +type serverConfig struct { + Host string `env:"SOFT_SERVE_HOST" default:""` + Port int `env:"SOFT_SERVE_PORT" default:"23231"` + KeyPath string `env:"SOFT_SERVE_KEY_PATH" default:".ssh/soft_serve_server_ed25519"` + RepoPath string `env:"SOFT_SERVE_REPO_PATH" default:".repos"` + AuthKey string `env:"SOFT_SERVE_AUTH_KEY" default:""` +} + +func main() { + var cfg serverConfig + err := babyenv.Parse(&cfg) + if err != nil { + log.Fatalln(err) + } + s := soft.NewServer( + cfg.Host, + cfg.Port, + cfg.KeyPath, + cfg.RepoPath, + cfg.AuthKey, + ) + log.Printf("Starting SSH server on %s:%d\n", cfg.Host, cfg.Port) + err = s.ListenAndServe() + if err != nil { + log.Fatalln(err) + } +} diff --git a/config/config.go b/config/config.go index f36c943312f7b119283fa332df9fe8dd53aabe8d..8eafe28106c904b2036b2696eb470c97b19c7ea6 100644 --- a/config/config.go +++ b/config/config.go @@ -6,8 +6,8 @@ import ( "fmt" "os" "path/filepath" - "soft-serve/git" + "github.com/charmbracelet/soft/git" gg "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" ) diff --git a/go.mod b/go.mod index c7408bd7120adf343dfb9e4084c5edbbe8d21f2e..d1ad65ecf9fb3e5b05acb5dbddcad2472d29f268 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module soft-serve +module github.com/charmbracelet/soft go 1.17 diff --git a/main.go b/main.go deleted file mode 100644 index 9ee1f8d3bd2d5b26d2b3ca36e2dd643878a9821d..0000000000000000000000000000000000000000 --- a/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "fmt" - "log" - "soft-serve/config" - "soft-serve/git" - "soft-serve/tui" - - "github.com/charmbracelet/wish" - bm "github.com/charmbracelet/wish/bubbletea" - gm "github.com/charmbracelet/wish/git" - lm "github.com/charmbracelet/wish/logging" - "github.com/gliderlabs/ssh" - - "github.com/meowgorithm/babyenv" -) - -type serverConfig struct { - Port int `env:"SOFT_SERVE_PORT" default:"23231"` - Host string `env:"SOFT_SERVE_HOST" default:""` - InitKey string `env:"SOFT_SERVE_REPO_KEY" default:""` - KeyPath string `env:"SOFT_SERVE_KEY_PATH" default:".ssh/soft_serve_server_ed25519"` - RepoPath string `env:"SOFT_SERVE_REPO_PATH" default:".repos"` -} - -func main() { - var scfg serverConfig - var cfg *config.Config - var err error - err = babyenv.Parse(&scfg) - if err != nil { - log.Fatalln(err) - } - rs := git.NewRepoSource(scfg.RepoPath) - cfg, err = config.NewConfig(scfg.Host, scfg.Port, scfg.InitKey, rs) - if err != nil { - log.Fatalln(err) - } - s, err := wish.NewServer( - ssh.PublicKeyAuth(cfg.PublicKeyHandler), - ssh.PasswordAuth(cfg.PasswordHandler), - wish.WithAddress(fmt.Sprintf("%s:%d", scfg.Host, scfg.Port)), - wish.WithHostKeyPath(scfg.KeyPath), - wish.WithMiddlewares( - bm.Middleware(tui.SessionHandler(cfg)), - gm.Middleware(scfg.RepoPath, cfg), - lm.Middleware(), - ), - ) - if err != nil { - log.Fatalln(err) - } - log.Printf("Starting SSH server on %s:%d\n", scfg.Host, scfg.Port) - err = s.ListenAndServe() - if err != nil { - log.Fatalln(err) - } -} diff --git a/main.tf b/main.tf deleted file mode 100644 index 192b4852a679e16b21b11a4b0d6f7ad8c87be255..0000000000000000000000000000000000000000 --- a/main.tf +++ /dev/null @@ -1,45 +0,0 @@ -terraform { - backend "s3" { - bucket = "charm-terraform-backend" - key = "soft-serve-development" - region = "us-east-1" - } -} - -variable "environment" { - default = "development" -} - -variable "aws_region" { - default = "us-east-1" -} - -variable "app_image" { - default = "ghcr.io/charmbracelet/soft-serve-internal:snapshot" -} - -variable "force_new_deployment" { - default = false -} - -variable "authorization_keys" { - default = "" -} - -module "soft_serve" { - # source = "../terraform-aws-soft-serve" - source = "app.terraform.io/charm/soft-serve/aws" - version = "0.3.2" - - environment = var.environment - aws_region = var.aws_region - ecs_task_execution_role_name = "softServeEcsTaskExecutionRole-${var.environment}" - app_image = var.app_image - app_count = 2 - app_ssh_port = 23231 - fargate_cpu = "1024" - fargate_memory = "2048" - force_new_deployment = var.force_new_deployment - app_use_default_ssh_port = true - authorization_keys = var.authorization_keys -} diff --git a/server.go b/server.go new file mode 100644 index 0000000000000000000000000000000000000000..fc5ae2a24f058545ada0a409d69033521070e24b --- /dev/null +++ b/server.go @@ -0,0 +1,44 @@ +package soft + +import ( + "fmt" + "log" + + "github.com/charmbracelet/soft/config" + "github.com/charmbracelet/soft/git" + "github.com/charmbracelet/soft/tui" + + "github.com/charmbracelet/wish" + bm "github.com/charmbracelet/wish/bubbletea" + gm "github.com/charmbracelet/wish/git" + lm "github.com/charmbracelet/wish/logging" + "github.com/gliderlabs/ssh" +) + +// NewServer returns a new *ssh.Server configured to serve Soft Serve. The SSH +// server key-pair will be created if none exists. An initial admin SSH public +// key can be provided with authKey. If authKey is provided, access will be +// restricted to that key. If authKey is not provided, the server will be +// publicly writable until configured otherwise by cloning the `config` repo. +func NewServer(host string, port int, serverKeyPath string, repoPath string, authKey string) *ssh.Server { + rs := git.NewRepoSource(repoPath) + cfg, err := config.NewConfig(host, port, authKey, rs) + if err != nil { + log.Fatalln(err) + } + s, err := wish.NewServer( + ssh.PublicKeyAuth(cfg.PublicKeyHandler), + ssh.PasswordAuth(cfg.PasswordHandler), + wish.WithAddress(fmt.Sprintf("%s:%d", host, port)), + wish.WithHostKeyPath(serverKeyPath), + wish.WithMiddlewares( + bm.Middleware(tui.SessionHandler(cfg)), + gm.Middleware(repoPath, cfg), + lm.Middleware(), + ), + ) + if err != nil { + log.Fatalln(err) + } + return s +} diff --git a/tui/bubble.go b/tui/bubble.go index 400a249ee7c813f3b3b9119c978e5586442e2ecf..ef899922505aba30939cbc53a855cdf1dfe97a04 100644 --- a/tui/bubble.go +++ b/tui/bubble.go @@ -2,15 +2,15 @@ package tui import ( "fmt" - "soft-serve/config" - "soft-serve/git" - "soft-serve/tui/bubbles/repo" - "soft-serve/tui/bubbles/selection" - "soft-serve/tui/style" "strings" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/soft/config" + "github.com/charmbracelet/soft/git" + "github.com/charmbracelet/soft/tui/bubbles/repo" + "github.com/charmbracelet/soft/tui/bubbles/selection" + "github.com/charmbracelet/soft/tui/style" ) type sessionState int diff --git a/tui/bubbles/commits/bubble.go b/tui/bubbles/commits/bubble.go index 593bceb81f111459bbf5a57a0bd45babdd723a06..662304a117acbd52503139274e01848e65938921 100644 --- a/tui/bubbles/commits/bubble.go +++ b/tui/bubbles/commits/bubble.go @@ -1,7 +1,7 @@ package commits import ( - "soft-serve/git" + "soft-serve/server/git" "strings" "github.com/charmbracelet/bubbles/viewport" diff --git a/tui/bubbles/repo/bubble.go b/tui/bubbles/repo/bubble.go index bf2ac0c591c724b58b391fbb32975980163ce3b1..e36effc6602c53a09f51d50edd64b417d3527a83 100644 --- a/tui/bubbles/repo/bubble.go +++ b/tui/bubbles/repo/bubble.go @@ -4,8 +4,6 @@ import ( "bytes" "fmt" "log" - "soft-serve/git" - "soft-serve/tui/style" "strconv" "text/template" "time" @@ -14,6 +12,8 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/glamour" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/soft/git" + "github.com/charmbracelet/soft/tui/style" "github.com/muesli/reflow/truncate" "github.com/muesli/reflow/wrap" ) diff --git a/tui/bubbles/selection/bubble.go b/tui/bubbles/selection/bubble.go index bd985657a2ec33c6e67cc42b222e721b055fee06..954222e1b53d8c067cb87923ab93be5bfeae91c6 100644 --- a/tui/bubbles/selection/bubble.go +++ b/tui/bubbles/selection/bubble.go @@ -1,11 +1,11 @@ package selection import ( - "soft-serve/tui/style" "strings" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/soft/tui/style" "github.com/muesli/reflow/truncate" ) diff --git a/tui/commands.go b/tui/commands.go index 7f777cc2e40db1418837fd27abfeb1fd4be2a8ee..3d8ebdbc0ae86c30e3c1e692b88ee32e8bd4e1c8 100644 --- a/tui/commands.go +++ b/tui/commands.go @@ -3,13 +3,13 @@ package tui import ( "fmt" "log" - "soft-serve/config" - "soft-serve/tui/bubbles/repo" - "soft-serve/tui/bubbles/selection" "time" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/soft/config" + "github.com/charmbracelet/soft/tui/bubbles/repo" + "github.com/charmbracelet/soft/tui/bubbles/selection" "github.com/muesli/termenv" ) diff --git a/tui/defaults.go b/tui/defaults.go deleted file mode 100644 index 2643296c08599b7f7d832dd7c1cdb65365cb69c3..0000000000000000000000000000000000000000 --- a/tui/defaults.go +++ /dev/null @@ -1,94 +0,0 @@ -package tui - -import ( - "os" - "path/filepath" - "soft-serve/git" - - gg "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing/object" -) - -const defaultReadme = "# Soft-Serve\n\n Welcome! You can configure your Soft-Serve server by cloning this repo and pushing changes.\n\n## Repos\n\n{{ range .Menu }}* {{ .Name }}{{ if .Note }} - {{ .Note }} {{ end }}\n - `git clone ssh://{{$.Host}}:{{$.Port}}/{{.Repo}}`\n{{ end }}" - -const defaultConfig = `{ - "name": "Soft-Serve", - "show_all_repos": true, - "host": "localhost", - "port": 23231, - "menu": [ - { - "name": "Home", - "repo": "config", - "note": "Configuration and content repo for this server" - } - ] -}` - -func createFile(path string, content string) error { - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - _, err = f.WriteString(content) - if err != nil { - return err - } - return f.Sync() -} - -func createDefaultConfigRepo(rs *git.RepoSource) error { - cn := "config" - err := rs.LoadRepos() - if err != nil { - return err - } - _, err = rs.GetRepo(cn) - if err == git.ErrMissingRepo { - cr, err := rs.InitRepo(cn, false) - if err != nil { - return err - } - - rp := filepath.Join(rs.Path, cn, "README.md") - err = createFile(rp, defaultReadme) - if err != nil { - return err - } - cp := filepath.Join(rs.Path, cn, "config.json") - err = createFile(cp, defaultConfig) - if err != nil { - return err - } - wt, err := cr.Repository.Worktree() - if err != nil { - return err - } - _, err = wt.Add("README.md") - if err != nil { - return err - } - _, err = wt.Add("config.json") - if err != nil { - return err - } - _, err = wt.Commit("Default init", &gg.CommitOptions{ - All: true, - Author: &object.Signature{ - Name: "Soft-Serve Server", - Email: "vt100@charm.sh", - }, - }) - if err != nil { - return err - } - err = rs.LoadRepos() - if err != nil { - return err - } - } else if err != nil { - return err - } - return nil -} diff --git a/tui/session.go b/tui/session.go index 51eedc361eb876aef7534ae193d0b049cf73767a..c91e5a31dc0152e125b24061d6ae007d30561575 100644 --- a/tui/session.go +++ b/tui/session.go @@ -2,9 +2,9 @@ package tui import ( "fmt" - "soft-serve/config" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/soft/config" "github.com/gliderlabs/ssh" )