Skip to content

Commit

Permalink
Merge pull request #1 from Conjur-Enterprise/CNJR-3040-auto-update
Browse files Browse the repository at this point in the history
CNJR-3040 Self Updating Summon Formula
  • Loading branch information
hughsaunders authored and GitHub Enterprise committed Dec 5, 2023
2 parents 6f7d83f + 7598c4a commit 663d19e
Show file tree
Hide file tree
Showing 17 changed files with 1,529 additions and 202 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cyberark_root.crt
.DS_Store
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).


## [0.0.1] - 2023-11-09

### Added
- Pipeline
- Self Updating formula for Summon.
7 changes: 3 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ contributor!

## Releasing

To update the Brew formula files follow the instructions in the release
section of the formula repositories.
The formulae in this repo use github-update.rb to find the latest release of each packaged tool. This means that this repo doesn't
have to be updated when the individual tools (eg summon) are updated.

For example to update `summon.rb` follow the instructions on
the [Summon release page](https://github.com/cyberark/summon/blob/main/CONTRIBUTING.md#releasing).
To release a new version of a homebrew packaged tool, all thats required is to create a new github release in that repository.
130 changes: 130 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env groovy

// Automated release, promotion and dependencies
properties([
// Include the automated release parameters for the build
release.addParams(),
// Dependencies of the project that should trigger builds
dependencies([
// Because of auto updating formulae, we don't actually need
// to release this repo everytime one of the projects releases.
// "conjur-enterprise/summon",
// "conjur-enterprise/summon-conjur",
// "conjur-enterprise/summon-aws-secrets",
// "conjur-enterprise/terraform-provider-conjur",
// "conjur-enterprise/secretless-broker"
])
])

// Performs release promotion. No other stages will be run
if (params.MODE == "PROMOTE") {
release.promote(params.VERSION_TO_PROMOTE) { infrapool, sourceVersion, targetVersion, assetDirectory ->
// Any assets from sourceVersion Github release are available in assetDirectory
// Any version number updates from sourceVersion to targetVersion occur here
// Any publishing of targetVersion artifacts occur here
// Anything added to assetDirectory will be attached to the Github Release

//Note: assetDirectory is on the infrapool agent, not the local Jenkins agent.
}
// Ths is the only part of promote relevant to homebrew-tools... here we copy
// the release from github enterprise to github.com
release.copyEnterpriseRelease(params.VERSION_TO_PROMOTE)
return
}

pipeline {
agent { label 'conjur-enterprise-common-agent' }

options {
timestamps()
buildDiscarder(logRotator(numToKeepStr: '30'))
}

triggers {
cron(getDailyCronString())
}

environment {
// Sets the MODE to the specified or autocalculated value as appropriate
MODE = release.canonicalizeMode()
}

stages {
// Aborts any builds triggered by another project that wouldn't include any changes
stage ("Skip build if triggering job didn't create a release") {
when {
expression {
MODE == "SKIP"
}
}
steps {
script {
currentBuild.result = 'ABORTED'
error("Aborting build because this build was triggered from upstream, but no release was built")
}
}
}

stage('Get InfraPool ExecutorV2 Agent(s)') {
steps{
script {
// Request ExecutorV2 agents for 1 hour
infrapool = getInfraPoolAgent.connected(type: "ExecutorV2", quantity: 1, duration: 1)[0]
}
}
}

// Generates a VERSION file based on the current build number and latest version in CHANGELOG.md
stage('Validate Changelog and set version') {
steps {
script {
updateVersion(infrapool, "CHANGELOG.md", "${BUILD_NUMBER}")
}
}
}
stage('Test Installs') {
steps {
script {
// Summon used to supply a github PAT to avoid
// hitting the github unauthenticated rate limit in CI.
// End users do not need to supply a token to install
// the formulae.
infrapool.agentSh 'tests/run-tests-in-docker.sh'
}
}
}

stage('Release') {
when {
expression {
MODE == "RELEASE"
}
}

steps {
script {
release(infrapool, { billOfMaterialsDirectory, assetDirectory ->
/* Publish release artifacts to all the appropriate locations
Copy any artifacts to assetDirectory on the infrapool node
to attach them to the Github release.
If your assets are on the infrapool node in the target
directory, use a copy like this:
infrapool.agentSh "cp target/* ${assetDirectory}"
Note That this will fail if there are no assets, add :||
if you want the release to succeed with no assets.
If your assets are in target on the main Jenkins agent, use:
infrapool.agentPut(from: 'target/', to: assetDirectory)
*/
})
}
}
}
}
post {
always {
releaseInfraPoolAgent()
}
}
}
52 changes: 14 additions & 38 deletions conjur-cli.rb
Original file line number Diff line number Diff line change
@@ -1,48 +1,24 @@
# typed: false
# frozen_string_literal: true

# This file was generated by GoReleaser. DO NOT EDIT.
require_relative 'github-update'

# This formulae will fetch the latest release from github. Versioning is
# still functional so homebrew will know which version is installed and
# when updates are available.
class ConjurCli < Formula
@@repo = "cyberark/conjur-cli-go"
@@ver, @@artifacts = GithubUpdate.getLatestRelease(@@repo)
desc "CyberArk Conjur command line interface"
homepage "https://conjur.org"
version "8.0.10-356"

on_macos do
if Hardware::CPU.arm?
url "https://github.com/cyberark/conjur-cli-go/releases/download/v8.0.10/conjur-cli-go_8.0.10_darwin_arm64.tar.gz"
sha256 "5f897d3eb407db005693211e3216e632170c6ff3555f85e82746fc93127ba521"

def install
bin.install "conjur"
end
end
if Hardware::CPU.intel?
url "https://github.com/cyberark/conjur-cli-go/releases/download/v8.0.10/conjur-cli-go_8.0.10_darwin_amd64.tar.gz"
sha256 "3bdb08304c054b7d38afcc775853fad86980f7b4fc7cc0b51a6e0f57181958ed"

def install
bin.install "conjur"
end
end
end

on_linux do
if Hardware::CPU.intel?
url "https://github.com/cyberark/conjur-cli-go/releases/download/v8.0.10/conjur-cli-go_8.0.10_linux_amd64.tar.gz"
sha256 "9dbb65fb57acf39f6a1bf8135e6f613d8605482ef3c0ba6d97f3152a8e3a2fb0"
homepage "https://github.com/#{@@repo}"
version @@ver

def install
bin.install "conjur"
end
end
if Hardware::CPU.arm? && Hardware::CPU.is_64_bit?
url "https://github.com/cyberark/conjur-cli-go/releases/download/v8.0.10/conjur-cli-go_8.0.10_linux_arm64.tar.gz"
sha256 "a11463300fd6108481858b66983b9576c446c792d211ce5f3bd100dfc26b7649"
@@artifact = @@artifacts["conjur-cli-go_#{@@ver}_#{OS.kernel_name.downcase}_#{GithubUpdate.arch(Hardware::CPU.type)}.tar.gz"]
url @@artifact["url"]
sha256 @@artifact["hash"]

def install
bin.install "conjur"
end
end
def install
bin.install "conjur"
end

test do
Expand Down
3 changes: 3 additions & 0 deletions dev-flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ class DevFlow < Formula
url "https://github.com/cyberark/dev-flow/releases/download/v0.1.0/dev-flow-darwin-amd64.tar.gz"
version "0.1.0"
sha256 "e2f5132cadf1a2ae2f20b89ec648c5026807af33a28ecd5457f771381b220b41"
deprecate! date: "2023-12-01", because: :repo_archived
# This repo is archived. There is only one release, so no need to update to automatic upgrades.
# This formula can be removed after the deprecation period.

def install
bin.install "dev-flow"
Expand Down
115 changes: 115 additions & 0 deletions github-update.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
require 'net/http'
require 'uri'
require 'json'

# Get release info from github
# Extracted into a class so it can be shared by multiple formulae.

class GithubUpdate
# net::http doesn't handle redirects, so we have to handle them
# here. It also doesnt have raise_for_status (like python requests)
# so we check the http response code and raise if its not a redirect
# or a 200.
def self.get_with_redirect(uri)
for _ in 1..20
# Ruby <3 includes net/http <0.1.1 where get_response doesn't take
# headers. Macos includes ruby 2.6.0, and to avoid users having to
# update ruby in order to brew install this package, we must make
# sure the library calls used are compatible with net/http v0.1.0
request = Net::HTTP::Get.new(uri)
using_token = false
# Homebrew seems to santize its environment variables, so we have to
# use a hombrew recognised environment variable.
if ENV.include? 'HOMEBREW_GITHUB_PACKAGE_TOKEN' and not(ENV['HOMEBREW_GITHUB_PACKAGE_TOKEN'].empty?)
using_token = true
# While github allows unauthenticated requests, the rate limit is low
# and easily hit in CI systems. To avoid this, we allow a GITHUB_TOKEN
# to be specified.
request["Authorization"] = "token #{ENV['HOMEBREW_GITHUB_PACKAGE_TOKEN']}"
end
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http|
http.request(request)
}
redirect = response.header['location']
if redirect != nil
uri = URI.parse(response.header['location'])
elsif response.code == 200.to_s
return response
else
body = response.body
if body.include? "rate limit"
if using_token
raise "Github rate limit exceeded :( "\
"A token was provided, check its valid and has quota."
else
raise "Github rate limit exceeded :( "\
"Rate limits are higher for authenticated users so try with a "\
"Github Personal Access Token eg: " \
"HOMEBREW_GITHUB_PACKAGE_TOKEN=YOUR_PAT_HERE brew install ... "
end
else
raise "Failed to fetch #{response.uri} Code: #{response.code} Response: #{response.body}."
end
end
end
raise "Too many redirects fetching #{uri}"
end

def self.getLatestRelease(repo)

# Can't use graphql unauthenticated, so have to use v3/REST API.

# Find the latest release
releases_uri = URI.parse("https://api.github.com/repos/#{repo}/releases")
releases_response = self.get_with_redirect(releases_uri)
releases = JSON.parse(releases_response.body)
raise "No GitHub releases found for repo #{repo}" if releases.empty?
latest = releases[0]

ver = latest["tag_name"].delete_prefix("v")

# Get list of artifacts from release
artifacts_uri = URI.parse(latest["assets_url"])
artifacts_response = self.get_with_redirect(artifacts_uri)
artifacts_json = JSON.parse(artifacts_response.body)

# Find hashes file generated by goreleaser in list of release assets
hashes_artifact_matches = artifacts_json.filter do |a|
a['name'].include? "SHA256SUMS"
end
if hashes_artifact_matches.empty?
raise "SHA256SUMS asset not found attached to github release #{releases_uri}"
end
hashes_artifact = hashes_artifact_matches[0]

# Download Hashes file
hashes_uri = URI.parse(hashes_artifact['browser_download_url'])
hashes_response = self.get_with_redirect(hashes_uri)
hashes_txt = hashes_response.body

# Parse hashes file into { filename => {'hash' => hash}}
artifacts = {}
for line in hashes_txt.split("\n") do
hash, file = line.split()
artifacts[file] = {"hash" => hash}
end

# Add download url to each artifact
# After this loop we have { filename => {'hash' => hash, 'url' => url}}
for artifact in artifacts_json do
name = artifact['name']
if artifacts.key? name
artifacts[name]['url'] = artifact['browser_download_url']
end
end
return ver, artifacts
end

# Map homebrew to goreleaser arch types
def self.arch(type)
return {
"intel" => "amd64",
"arm" => "arm64"
}[String(type)]
end
end
Loading

0 comments on commit 663d19e

Please sign in to comment.