Skip to content
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
4 changes: 2 additions & 2 deletions bin/github-build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
begin
exit(GHB::Application.new(ARGV).execute)
rescue GHB::ConfigError => e
puts("Error: #{e.message}")
warn("Error: #{e.message}")
exit(1)
rescue StandardError => e
puts("Error: #{e.message}")
warn("Error: #{e.message}")
warn(e.backtrace.join("\n")) if ENV['DEBUG']
exit(1)
end
4 changes: 2 additions & 2 deletions lib/ghb/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,12 @@ def workflow_set_defaults

@new_workflow.run_name = @old_workflow.run_name unless @old_workflow.run_name.nil?
@new_workflow.permissions =
if @old_workflow.permissions.is_a?(Hash) && @old_workflow.permissions.any?
if @old_workflow.permissions.any?
@old_workflow.permissions
else
{ contents: 'read', 'pull-requests': 'read' }
end
@new_workflow.env = @old_workflow.env.is_a?(Hash) ? @old_workflow.env : {}
@new_workflow.env = @old_workflow.env
@new_workflow.defaults = @old_workflow.defaults || {}
@new_workflow.concurrency = @old_workflow.concurrency || {}
end
Expand Down
12 changes: 5 additions & 7 deletions lib/ghb/aws_job_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,19 @@ def build
return unless File.exist?('.aws')

puts(' Adding aws commands...')
needs = @new_workflow.jobs.keys.map(&:to_s)
base_condition = "always() && (needs.variables.outputs.DEPLOY_ON_BETA == '1' || needs.variables.outputs.DEPLOY_ON_RC == '1' || needs.variables.outputs.DEPLOY_ON_PROD == '1')"
job_conditions = @new_workflow.jobs.keys.map { |job_name| "needs.#{job_name}.result != 'failure'" }
if_statement = ([base_condition] + job_conditions).join(' && ')
needs = @new_workflow.deploy_needs
if_statement = @new_workflow.deploy_if_statement
old_workflow = @old_workflow

@new_workflow.do_job(:aws) do
copy_properties(old_workflow.jobs[id], %i[name permissions needs if runs_on environment concurrency outputs env defaults timeout_minutes strategy continue_on_error container services uses with secrets])
copy_properties(old_workflow.jobs[id])
do_name('AWS')
do_runs_on(DEFAULT_UBUNTU_VERSION)
do_needs(needs)
do_if("${{#{if_statement}}}")
do_if(if_statement)

do_step('AWS Commands') do
copy_properties(find_step(old_workflow.jobs[:aws]&.steps, name), %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(find_step(old_workflow.jobs[:aws]&.steps, name))
do_uses("cloud-officer/ci-actions/aws@#{CI_ACTIONS_VERSION}")

if with.empty?
Expand Down
22 changes: 10 additions & 12 deletions lib/ghb/code_deploy_job_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,21 @@ def build
private

def build_codedeploy_job
needs = @new_workflow.jobs.keys.map(&:to_s)
base_condition = "always() && (needs.variables.outputs.DEPLOY_ON_BETA == '1' || needs.variables.outputs.DEPLOY_ON_RC == '1' || needs.variables.outputs.DEPLOY_ON_PROD == '1')"
job_conditions = @new_workflow.jobs.keys.map { |job_name| "needs.#{job_name}.result != 'failure'" }
if_statement = ([base_condition] + job_conditions).join(' && ')
needs = @new_workflow.deploy_needs
if_statement = @new_workflow.deploy_if_statement
code_deploy_pre_steps = @code_deploy_pre_steps
old_workflow = @old_workflow

@new_workflow.do_job(:codedeploy) do
copy_properties(old_workflow.jobs[id], %i[name permissions needs if runs_on environment concurrency outputs env defaults timeout_minutes strategy continue_on_error container services uses with secrets])
copy_properties(old_workflow.jobs[id])
do_name('Code Deploy')
do_runs_on(DEFAULT_UBUNTU_VERSION)
do_needs(needs)
do_if("${{#{if_statement}}}")
do_if(if_statement)

if code_deploy_pre_steps.empty?
do_step('Checkout') do
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name), %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name))
do_uses("cloud-officer/ci-actions/codedeploy/checkout@#{CI_ACTIONS_VERSION}")
do_with({ 'ssh-key': '${{secrets.SSH_KEY}}', 'github-token': '${{secrets.GH_PAT}}' }) if with.empty?
end
Expand All @@ -52,20 +50,20 @@ def build_codedeploy_job
end

do_step('Update Packages') do
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name), %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name))
do_if("${{needs.variables.outputs.UPDATE_PACKAGES == '1'}}")
do_shell('bash')
do_run('touch update-packages')
end

do_step('Zip') do
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name), %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name))
do_shell('bash')
do_run('zip --quiet --recurse-paths "${{needs.variables.outputs.BUILD_NAME}}.zip" ./*') if run.nil?
end

do_step('S3Copy') do
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name), %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(find_step(old_workflow.jobs[:codedeploy]&.steps, name))
do_uses("cloud-officer/ci-actions/codedeploy/s3copy@#{CI_ACTIONS_VERSION}")

if with.empty?
Expand All @@ -89,14 +87,14 @@ def build_environment_jobs

%w[beta rc prod].each do |environment|
@new_workflow.do_job(:"#{environment}_deploy") do
copy_properties(old_workflow.jobs[id], %i[name permissions needs if runs_on environment concurrency outputs env defaults timeout_minutes strategy continue_on_error container services uses with secrets])
copy_properties(old_workflow.jobs[id])
do_name("#{environment.capitalize} Deploy")
do_runs_on(DEFAULT_UBUNTU_VERSION)
do_needs(%w[variables codedeploy])
do_if("${{always() && needs.codedeploy.result == 'success' && needs.variables.outputs.DEPLOY_ON_#{environment.upcase} == '1'}}")

do_step("#{environment.capitalize} Deploy") do
copy_properties(find_step(old_workflow.jobs[:"#{environment}_deploy"]&.steps, name), %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(find_step(old_workflow.jobs[:"#{environment}_deploy"]&.steps, name))
do_uses("cloud-officer/ci-actions/codedeploy/deploy@#{CI_ACTIONS_VERSION}")

if with.empty?
Expand Down
2 changes: 1 addition & 1 deletion lib/ghb/dependabot_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def save_dependencies_workflow
end

do_step('Licenses') do
copy_properties(new_workflow.jobs[:licenses]&.steps&.first, %i[id if uses run shell with env continue_on_error timeout_minutes])
copy_properties(new_workflow.jobs[:licenses]&.steps&.first)
do_uses("cloud-officer/ci-actions/soup@#{CI_ACTIONS_VERSION}")

if with.empty?
Expand Down
12 changes: 6 additions & 6 deletions lib/ghb/file_scanner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ def cached_file_read(path)
@file_cache[path] ||= File.read(path)
end

# Pure Ruby file finder - avoids shell command injection (SEC-001, SEC-002)
# @param path [String] starting directory path
# @param pattern [Regexp] file pattern to match
# @param excluded_paths [Array<String>] paths to exclude (partial matches)
# @param max_depth [Integer, nil] maximum directory depth (nil for unlimited)
# @return [Array<String>] list of matching file paths
# Builds the list of excluded directory patterns from languages.yaml.
# Combines install_dirs from all dependency entries with the top-level excluded_dirs.
# @return [Array<String>] directory names to exclude (e.g., ['node_modules', 'vendor', '.git'])
Expand All @@ -42,6 +36,12 @@ def excluded_dirs_from_config
end
end

# Pure Ruby file finder - avoids shell command injection (SEC-001, SEC-002)
# @param path [String] starting directory path
# @param pattern [Regexp] file pattern to match
# @param excluded_paths [Array<String>] paths to exclude (partial matches)
# @param max_depth [Integer, nil] maximum directory depth (nil for unlimited)
# @return [Array<String>] list of matching file paths
def find_files_matching(path, pattern, excluded_paths = [], max_depth: nil)
matches = []
base_depth = path.count(File::SEPARATOR)
Expand Down
Loading
Loading