diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a984a75 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +.git* +.dockerignore +.env.* +*.env +.rubocop* +.solargraph* +.eslintrc.js +.rspec +.vscode +.circleci +.storybook +commitlint.config.js +Procfile.dev +stylelint.config.js +**/node_modules +coverage +app/frontend/stories +app/frontend/tests +config/master.key +config/credentials.yml.enc +public/vite-dev +public/vite-test +log +spec +Procfile.dev +vitest.config.ts +rubocop-* +**/.keep \ No newline at end of file diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..57ccbaf --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +source .env \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e64a388 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: Release + +on: + workflow_dispatch: + +jobs: + release: + runs-on: ubuntu-latest + + name: "Bump version and publish docker image" + + permissions: write-all + + steps: + - name: Check out + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Version Bump + run: | + npm install -g commitlint semantic-release semantic-release-github-actions-tags @semantic-release/changelog @semantic-release/git + npx semantic-release --ci + env: + GH_TOKEN: ${{ secrets.GH_AUTH_TOKEN }} + + - name: Build Docker Image + env: + POSTGRES_USER: ${{ env.POSTGRES_USER }} + POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + run: | + docker-compose -f docker-compose.yml build + + - name: Authenticate to GitHub Container Registry + run: echo ${{ secrets.GH_AUTH_TOKEN }} | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + + - name: Push Docker Image to GitHub Packages + run: | + NEW_VERSION=$(node -p "require('./package.json').version") + docker tag osc ghcr.io/${{ github.repository_owner }}/osc:${NEW_VERSION} + docker push ghcr.io/${{ github.repository_owner }}/osc:${NEW_VERSION} + env: + GHCR_PAT: ${{ secrets.GH_AUTH_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..9d0c805 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,71 @@ +name: Ruby + +on: + pull_request: + branches: + - main + - dev + +jobs: + test: + + runs-on: ubuntu-latest + + env: + POSTGRES_USER: osc + POSTGRES_PASSWORD: osc + POSTGRES_HOST: localhost + POSTGRES_DB: osc_test + + services: + postgres: + image: postgres:15-alpine + env: + POSTGRES_USER: ${{ env.POSTGRES_USER }} + POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + POSTGRES_DB: ${{ env.POSTGRES_DB }} + POSTGRES_HOST_AUTH_METHOD: trust + ports: ['5432:5432'] + options: + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: 19.x + cache: 'yarn' + + - name: Set up Yarn + run: npm install -g yarn + + - name: Install Ruby dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Install Node.js dependencies + run: yarn install + + - name: Prepare database + env: + DATABASE_URL: postgres://${{ env.POSTGRES_USER }}:${{ env.POSTGRES_PASSWORD }}@${{ env.POSTGRES_HOST }}:5432/${{ env.POSTGRES_DB }} + RAILS_ENV: test + run: | + bundle exec rails db:prepare + + - name: Run tests + env: + DATABASE_URL: postgres://${{ env.POSTGRES_USER }}:${{ env.POSTGRES_PASSWORD }}@${{ env.POSTGRES_HOST }}:5432/${{ env.POSTGRES_DB }} + run: bundle exec rspec + + - name: Run Vite tests + run: yarn test diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bf7643c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,57 @@ +ARG RUBY_VERSION=3.2.2 + +FROM ruby:$RUBY_VERSION AS BUILD_IMAGE + +ARG BUNDLER_VERSION=2.4.17 +ARG NODE_MAJOR_VERSION=20 + +ADD . /osc +WORKDIR /osc + +# Install basic packages +RUN apt-get update && apt-get install -y build-essential libvips postgresql-client ca-certificates curl gnupg + +# Install Node +RUN mkdir -p /etc/apt/keyrings +RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg +RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR_VERSION.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list +RUN apt-get update && apt-get install -y nodejs +RUN npm i -g yarn && yarn set version stable + +# Clean up apt +RUN apt-get clean && rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man + +# Rails app lives here +WORKDIR /osc + +# Set production environment +ENV RAILS_LOG_TO_STDOUT="1" +ENV RAILS_SERVE_STATIC_FILES true +ENV RAILS_ENV production +# ENV BUNDLE_WITHOUT development +ENV NODE_ENV production + +# Install application gems +COPY Gemfile Gemfile.lock ./ +RUN gem uninstall bundler && gem install bundler -v $BUNDLER_VERSION +RUN bundle install + +# Install npm packages +COPY package.json yarn.lock ./ +RUN yarn install + +# Copy application code +COPY ./docker_copy_files.sh . +RUN chmod +x ./docker_copy_files.sh +RUN ./docker_copy_files.sh + +# Precompile bootsnap code for faster boot times +RUN bundle exec bootsnap precompile --gemfile app/ lib/ + +# Precompiling assets for production without requiring secret RAILS_MASTER_KEY +RUN SECRET_KEY_BASE=DUMMY bundle exec rails assets:precompile + +# Entrypoint prepares the database +ENTRYPOINT ["/osc/bin/docker-entrypoint"] + +EXPOSE 3000 \ No newline at end of file diff --git a/app/policies/protocol_policy.rb b/app/policies/protocol_policy.rb index 21498c3..2f00f4c 100644 --- a/app/policies/protocol_policy.rb +++ b/app/policies/protocol_policy.rb @@ -5,4 +5,8 @@ class Scope < Scope def options? standard_auth(:options) end + + def execute? + standard_auth(:options) + end end diff --git a/config/application.rb b/config/application.rb index df80987..367f05c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -17,7 +17,6 @@ class Application < Rails::Application # in config/environments, which are processed later. # config.time_zone = "Pacific Time (US & Canada)" - # config.eager_load_paths << Rails.root.join("extras") config.autoload_paths += %W(#{config.root}/lib) @@ -38,7 +37,8 @@ class Application < Rails::Application config.active_record.yaml_column_permitted_classes = [Symbol, Hash, Array, Time, Date, ActiveRecord::Base, ActiveSupport::HashWithIndifferentAccess] - # config.active_job.queue_adapter = :good_job + config.credentials.key_path = Rails.root.join("config/secrets/master.key") + config.credentials.content_path = Rails.root.join("config/secrets/credentials.yml.enc") # Establish db connection upon entering rails console console do diff --git a/config/database.yml b/config/database.yml index 14eb634..470e4a9 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,19 +1,3 @@ -# PostgreSQL. Versions 9.3 and up are supported. -# -# Install the pg driver: -# gem install pg -# On macOS with Homebrew: -# gem install pg -- --with-pg-config=/usr/local/bin/pg_config -# On macOS with MacPorts: -# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config -# On Windows: -# gem install pg -# Choose the win32 build. -# Install PostgreSQL and put its /bin directory on your path. -# -# Configure Using Gemfile -# gem "pg" -# default: &default adapter: postgresql encoding: unicode @@ -25,33 +9,6 @@ development: <<: *default database: osc_development - # The specified database role being used to connect to postgres. - # To create additional roles in postgres see `$ createuser --help`. - # When left blank, postgres will use the default role. This is - # the same name as the operating system user running Rails. - #username: osc - - # The password associated with the postgres role (username). - #password: - - # Connect on a TCP socket. Omitted by default since the client uses a - # domain socket that doesn't need configuration. Windows does not have - # domain sockets, so uncomment these lines. - #host: localhost - - # The TCP port the server listens on. Defaults to 5432. - # If your server runs on a different port number, change accordingly. - #port: 5432 - - # Schema search path. The server defaults to $user,public - #schema_search_path: myapp,sharedapp,public - - # Minimum log levels, in increasing order: - # debug5, debug4, debug3, debug2, debug1, - # log, notice, warning, error, fatal, and panic - # Defaults to warning. - #min_messages: notice - # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. @@ -59,28 +16,12 @@ test: <<: *default database: osc_test -# As with config/credentials.yml, you never want to store sensitive information, -# like your database password, in your source code. If your source code is -# ever seen by anyone, they now have access to your database. -# -# Instead, provide the password or a full connection URL as an environment -# variable when you boot the app. For example: -# -# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" -# -# If the connection URL is provided in the special DATABASE_URL environment -# variable, Rails will automatically merge its configuration values on top of -# the values provided in this file. Alternatively, you can specify a connection -# URL environment variable explicitly: -# -# production: -# url: <%= ENV["MY_APP_DATABASE_URL"] %> -# # Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full overview on how database connection configuration can be specified. # production: <<: *default database: osc_production - username: osc - password: <%= ENV["OSC_DATABASE_PASSWORD"] %> + host: <%= ENV["POSTGRES_HOST"] || "localhost" %> + username: <%= ENV["POSTGRES_USER"] || ENV["USER"] %> + password: <%= ENV["POSTGRES_PASSWORD"] %> \ No newline at end of file diff --git a/config/secrets/credentials.yml.enc b/config/secrets/credentials.yml.enc new file mode 100644 index 0000000..1546b77 --- /dev/null +++ b/config/secrets/credentials.yml.enc @@ -0,0 +1 @@ +xHhAOBZLKEaTJ/9qV9XhMqoBGlI7ImpGAEQhUTc1VJ9kgcp8K3H50oFMew3XPO4WNp30MMAy3xRQ4d2/xLG8PDUZ9dINxOae+lCro/vbJPNe3eYkVHAB/2O0iSeFSrr+Cg2D/NsM0cWy4X0H/E7+b0xNah/NvBokM51/OUOGa2q6c7621WzOHz7ODElpVeNkF3UrUHnbFfKCstATj4sjkV9HYx3iDoMmANITpvG/Z+To75zBacVqGJ59+G3bsdsnW61FuTdIsLMElgzgZY1FKzJMnDG8VA6QeBG2YzPnzgV+07RzwTFZ3PbsFi7m134SOZzoX6DlQX+zVtUM8d6qO465uLM3VPllTLgb8sy4/vdElolna2rgMsiXsd/P47UJMAwbdfPgVG9sWJ+uiUhHEXdswPd3LchffncH--7YUaJqXSCfgaa9GR--iy2s+hie4ej5vbzXddVObw== \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..40a6ecd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.9' + +services: + postgres: + image: postgres:15.4-alpine + environment: + POSTGRES_USER: "${POSTGRES_USER}" + POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" + volumes: + - postgres:/var/lib/postgresql/data + restart: always + + web: + image: osc_controller + build: . + command: > + bash -c "bin/docker-entrypoint" + volumes: + - .:/osc + - files:/osc/storage + - secrets:/osc/config/secrets + ports: + - "80:3000" + depends_on: + - postgres + environment: + RACK_ENV: "production" + RAILS_ENV: "production" + NODE_ENV: "production" + POSTGRES_USER: "${POSTGRES_USER}" + POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" + POSTGRES_HOST: postgres + restart: always + +volumes: + postgres: + files: + secrets: