Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MONGOID-5743 SSDLC Requirements #5834

Merged
merged 6 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: "Dry-Run Cleanup"
run-name: "Dry Run Cleanup for ${{ github.ref }}"

on:
workflow_dispatch:
inputs:
confirm:
description: Indicate whether you want this workflow to run (must be "true")
required: true
type: string
tag:
description: The name of the tag (and release) to clean up
required: true
type: string

jobs:
release:
name: "Dry-Run Cleanup"
environment: release
runs-on: 'ubuntu-latest'
if: ${{ inputs.confirm == 'true' }}

permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: write

# required by the mongodb-labs/drivers-github-tools/setup@v2 step
# also required by `rubygems/release-gem`
id-token: write

steps:
- name: "Run the cleanup action"
uses: mongodb-labs/drivers-github-tools/ruby/cleanup@v2
with:
app_id: ${{ vars.APP_ID }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
tag: ${{ inputs.tag }}
79 changes: 79 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: "CodeQL"

on:
push:
pull_request:
schedule:
- cron: '20 0 * * 0'

jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: 'ubuntu-latest'
timeout-minutes: 360
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read

strategy:
fail-fast: false
matrix:
include:
- language: ruby
build-mode: none
steps:
- name: Checkout repository
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config: |
paths-ignore:
- .evergreen
- spec
- perf
- examples
- test-apps
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality

# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

67 changes: 67 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: "Mongoid Release"
run-name: "Mongoid Release for ${{ github.ref }}"

on:
workflow_dispatch:
inputs:
dry_run:
description: Whether this is a dry run or not
required: true
default: true
type: boolean

env:
SILK_ASSET_GROUP: mongoid
RELEASE_MESSAGE_TEMPLATE: |
Version {0} of the [Mongoid ODM for MongoDB](https://rubygems.org/gems/mongoid) is now available.

**Release Highlights**

TODO: one or more paragraphs describing important changes in this release

**Documentation**

Documentation is available at [MongoDB.com](https://www.mongodb.com/docs/mongoid/current/).

**Installation**

You may install this version via RubyGems, with:

gem install --version {0} mongoid

jobs:
release:
name: "Mongoid Release"
environment: release
runs-on: 'ubuntu-latest'

permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: write

# required by the mongodb-labs/drivers-github-tools/setup@v2 step
# also required by `rubygems/release-gem`
id-token: write

steps:
- name: "Run the publish action"
uses: mongodb-labs/drivers-github-tools/ruby/publish@v2
with:
app_id: ${{ vars.APP_ID }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
aws_region_name: ${{ vars.AWS_REGION_NAME }}
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
dry_run: ${{ inputs.dry_run }}
gem_name: mongoid
product_name: Mongoid
product_id: mongoid
release_message_template: ${{ env.RELEASE_MESSAGE_TEMPLATE }}
silk_asset_group: ${{ env.SILK_ASSET_GROUP }}
65 changes: 44 additions & 21 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# rubocop:todo all

require "bundler"
require "bundler/gem_tasks"
Bundler.setup

ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
Expand All @@ -11,25 +10,53 @@ $: << File.join(ROOT, 'spec/shared/lib')

require "rake"
require "rspec/core/rake_task"
require 'mrss/spec_organizer'

$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
require "mongoid/version"

tasks = Rake.application.instance_variable_get('@tasks')
tasks['release:do'] = tasks.delete('release')

task :gem => :build
# stands in for the Bundler-provided `build` task, which builds the
# gem for this project. Our release process builds the gems in a
# particular way, in a GitHub action. This task is just to help remind
# developers of that fact.
task :build do
system "gem build mongoid.gemspec"
abort <<~WARNING
`rake build` does nothing in this project. The gem must be built via
the `Mongoid Release` action on GitHub, which is triggered manually when
a new release is ready.
WARNING
end

task :install => :build do
system "sudo gem install mongoid-#{Mongoid::VERSION}.gem"
# `rake version` is used by the deployment system so get the release version
# of the product beng deployed. It must do nothing more than just print the
# product version number.
#
# See the mongodb-labs/driver-github-tools/ruby/publish Github action.
desc "Print the current value of Mongoid::VERSION"
task :version do
require 'mongoid/version'

puts Mongoid::VERSION
end

# overrides the default Bundler-provided `release` task, which also
# builds the gem. Our release process assumes the gem has already
# been built (and signed via GPG), so we just need `rake release` to
# push the gem to rubygems.
task :release do
raise "Please use ./release.sh to release"
require 'mongoid/version'

if ENV['GITHUB_ACTION'].nil?
abort <<~WARNING
`rake release` must be invoked from the `Mongoid Release` GitHub action,
and must not be invoked locally. This ensures the gem is properly signed
and distributed by the appropriate user.

Note that it is the `rubygems/release-gem@v1` step in the `Mongoid Release`
action that invokes this task. Do not rename or remove this task, or the
release-gem step will fail. Reimplement this task with caution.

mongoid-#{Mongoid::VERSION}.gem was NOT pushed to RubyGems.
WARNING
end

system 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
end

RSpec::Core::RakeTask.new("spec") do |spec|
Expand Down Expand Up @@ -96,6 +123,8 @@ RUN_PRIORITY = %i(
)

def spec_organizer
require 'mrss/spec_organizer'

Mrss::SpecOrganizer.new(
root: ROOT,
classifiers: CLASSIFIERS,
Expand Down Expand Up @@ -131,16 +160,10 @@ task :docs => 'docs:yard'
namespace :docs do
desc "Generate yard documentation"
task :yard do
require "mongoid/version"

out = File.join('yard-docs', Mongoid::VERSION)
FileUtils.rm_rf(out)
system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
end
end

namespace :release do
task :check_private_key do
unless File.exist?('gem-private_key.pem')
raise "No private key present, cannot release"
end
end
end
16 changes: 15 additions & 1 deletion lib/mongoid/criteria/queryable/extensions/numeric.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,21 @@ module ClassMethods
#
# @return [ Object ] The converted number.
def __numeric__(object)
object.to_s.match?(/\A[-+]?[0-9]*[0-9.]0*\z/) ? object.to_i : Float(object)
str = object.to_s
raise ArgumentError if str.empty?

# These requirements seem a bit odd, but they're explicitly specified in the tests,
# so we're obligated to keep them, for now. (This code was rewritten from a one-line
# regex, due to security concerns with a polynomial regex being used on uncontrolled
# data).

str = str.chop if str.end_with?('.')
return 0 if str.empty?

result = Integer(str) rescue Float(object)

integer = result.to_i
integer == result ? integer : result
end

# Evolve the object to an integer.
Expand Down
17 changes: 11 additions & 6 deletions lib/mongoid/fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ module Fields
# @api private
INVALID_BSON_CLASSES = [ BSON::Decimal128, BSON::Int32, BSON::Int64 ].freeze

# The suffix for generated translated fields.
#
# @api private
TRANSLATIONS_SFX = '_translations'

module ClassMethods
# Returns the list of id fields for this model class, as both strings
# and symbols.
Expand Down Expand Up @@ -101,8 +106,8 @@ def cleanse_localized_field_names(name)
ar.each_with_index do |fn, i|
key = fn
unless klass.fields.key?(fn) || klass.relations.key?(fn)
if tr = fn.match(/(.*)_translations\z/)&.captures&.first
key = tr
if fn.end_with?(TRANSLATIONS_SFX)
key = fn.delete_suffix(TRANSLATIONS_SFX)
else
key = fn
end
Expand Down Expand Up @@ -725,11 +730,11 @@ def create_field_check(name, meth)
# @api private
def create_translations_getter(name, meth)
generated_methods.module_eval do
re_define_method("#{meth}_translations") do
re_define_method("#{meth}#{TRANSLATIONS_SFX}") do
attributes[name] ||= {}
attributes[name].with_indifferent_access
end
alias_method :"#{meth}_t", :"#{meth}_translations"
alias_method :"#{meth}_t", :"#{meth}#{TRANSLATIONS_SFX}"
end
end

Expand All @@ -745,14 +750,14 @@ def create_translations_getter(name, meth)
# @api private
def create_translations_setter(name, meth, field)
generated_methods.module_eval do
re_define_method("#{meth}_translations=") do |value|
re_define_method("#{meth}#{TRANSLATIONS_SFX}=") do |value|
attribute_will_change!(name)
value&.transform_values! do |_value|
field.type.mongoize(_value)
end
attributes[name] = value
end
alias_method :"#{meth}_t=", :"#{meth}_translations="
alias_method :"#{meth}_t=", :"#{meth}#{TRANSLATIONS_SFX}="
end
end

Expand Down
Loading
Loading