From 42079695b6f96fda4ca9b8a052ac9310292011a0 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Wed, 28 May 2025 22:24:07 +0000 Subject: [PATCH 1/6] chore: Enable CI and Publishing --- .github/ISSUE_TEMPLATE/bug_report.md | 37 +++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++ .github/actions/build-docs/action.yml | 9 ++++ .github/actions/ci/action.yml | 25 +++++++++ .github/actions/publish-docs/action.yml | 15 ++++++ .github/actions/publish/action.yml | 28 ++++++++++ .github/pull_request_template.md | 21 ++++++++ .github/workflows/ci.yml | 54 +++++++++++++++++++ .github/workflows/lint-pr-title.yml | 12 +++++ .github/workflows/manual-publish-docs.yml | 22 ++++++++ .github/workflows/manual-publish.yml | 49 +++++++++++++++++ .github/workflows/release-please.yml | 65 +++++++++++++++++++++++ .github/workflows/stale.yml | 10 ++++ .release-please-manifest.json | 3 ++ release-please-config.json | 12 +++++ 16 files changed, 387 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/actions/build-docs/action.yml create mode 100644 .github/actions/ci/action.yml create mode 100644 .github/actions/publish-docs/action.yml create mode 100644 .github/actions/publish/action.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/lint-pr-title.yml create mode 100644 .github/workflows/manual-publish-docs.yml create mode 100644 .github/workflows/manual-publish.yml create mode 100644 .github/workflows/release-please.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.json diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..a9c8db8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Is this a support request?** +This issue tracker is maintained by LaunchDarkly SDK developers and is intended for feedback on the SDK code. If you're not sure whether the problem you are having is specifically related to the SDK, or to the LaunchDarkly service overall, it may be more appropriate to contact the LaunchDarkly support team; they can help to investigate the problem and will consult the SDK team if necessary. You can submit a support request by going [here](https://support.launchdarkly.com/hc/en-us/requests/new) or by emailing support@launchdarkly.com. + +Note that issues filed on this issue tracker are publicly accessible. Do not provide any private account information on your issues. If your problem is specific to your account, you should submit a support request as described above. + +**Describe the bug** +A clear and concise description of what the bug is. + +**To reproduce** +Steps to reproduce the behavior. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Logs** +If applicable, add any log output related to your problem. + +**SDK version** +The version of this SDK that you are using. + +**Language version, developer tools** +For instance, Go 1.11 or Ruby 2.5.3. If you are using a language that requires a separate compiler, such as C, please include the name and version of the compiler too. + +**OS/platform** +For instance, Ubuntu 16.04, Windows 10, or Android 4.0.3. If your code is running in a browser, please also include the browser type and version. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..e5673e2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Support request + url: https://support.launchdarkly.com/hc/en-us/requests/new + about: File your support requests with LaunchDarkly's support team diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..3f7d5bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I would love to see the SDK [...does something new...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context about the feature request here. diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml new file mode 100644 index 0000000..eddd44d --- /dev/null +++ b/.github/actions/build-docs/action.yml @@ -0,0 +1,9 @@ +name: Build Documentation +description: 'Build Documentation.' + +runs: + using: composite + steps: + - name: Build Documentation + shell: bash + run: cd docs && make html diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml new file mode 100644 index 0000000..229d7ac --- /dev/null +++ b/.github/actions/ci/action.yml @@ -0,0 +1,25 @@ +name: CI Workflow +description: 'Shared CI workflow.' +inputs: + ruby-version: + description: 'The version of ruby to setup and run' + required: true + +runs: + using: composite + steps: + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ inputs.ruby-version }} + + - name: Install dependencies + shell: bash + run: bundle install + + - name: Run tests + shell: bash + run: bundle exec rspec spec $SPEC_TAGS + + - name: Run RuboCop + shell: bash + run: bundle exec rubocop --parallel diff --git a/.github/actions/publish-docs/action.yml b/.github/actions/publish-docs/action.yml new file mode 100644 index 0000000..0a827c0 --- /dev/null +++ b/.github/actions/publish-docs/action.yml @@ -0,0 +1,15 @@ +name: Publish Documentation +description: 'Publish the documentation to GitHub Pages' +inputs: + token: + description: 'Token to use for publishing.' + required: true + +runs: + using: composite + steps: + - uses: launchdarkly/gh-actions/actions/publish-pages@publish-pages-v1.0.2 + name: 'Publish to Github pages' + with: + docs_path: docs/build/html/ + github_token: ${{inputs.token}} # For the shared action the token should be a GITHUB_TOKEN< diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml new file mode 100644 index 0000000..1dadf3e --- /dev/null +++ b/.github/actions/publish/action.yml @@ -0,0 +1,28 @@ +name: Publish Package +description: 'Publish the package to rubygems' +inputs: + dry_run: + description: 'Is this a dry run. If so no package will be published.' + required: true +outputs: + gem-hash: + description: "base64-encoded sha256 hashes of distribution files" + value: ${{ steps.gem-hash.outputs.gem-hash }} + +runs: + using: composite + steps: + - name: Build gemspec + shell: bash + run: gem build launchdarkly-server-sdk-ai.gemspec + + - name: Hash gem for provenance + id: gem-hash + shell: bash + run: | + echo "gem-hash=$(sha256sum launchdarkly-server-sdk-ai-*.gem | base64 -w0)" >> "$GITHUB_OUTPUT" + + - name: Publish Library + shell: bash + if: ${{ inputs.dry_run == 'false' }} + run: gem push launchdarkly-server-sdk-ai-*.gem diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..fc89ce0 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +**Requirements** + +- [ ] I have added test coverage for new or changed functionality +- [ ] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) +- [ ] I have validated my changes against all supported platform versions + +**Related issues** + +Provide links to any issues in this repository or elsewhere relating to this pull request. + +**Describe the solution you've provided** + +Provide a clear and concise description of what you expect to happen. + +**Describe alternatives you've considered** + +Provide a clear and concise description of any alternative solutions or features you've considered. + +**Additional context** + +Add any other context about the pull request here. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..057d2b9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: Run CI +on: + push: + branches: [ main ] + paths-ignore: + - '**.md' # Do not need to run CI for markdown changes. + pull_request: + branches: [ main ] + paths-ignore: + - '**.md' + +jobs: + build-linux: + runs-on: ubuntu-latest + + strategy: + matrix: + ruby-version: + - '3.0' + - '3.1' + - '3.2' + - jruby-9.4 + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # If you only need the current version keep this. + + - uses: ./.github/actions/ci + with: + ruby-version: ${{ matrix.ruby-version }} + + - uses: ./.github/actions/build-docs + if: ${{ !startsWith(matrix.ruby-version, 'jruby') }} + + build-windows: + runs-on: windows-latest + + defaults: + run: + shell: powershell + + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0 + + - name: Install dependencies + run: bundle install + + - name: Run tests + run: bundle exec rspec spec diff --git a/.github/workflows/lint-pr-title.yml b/.github/workflows/lint-pr-title.yml new file mode 100644 index 0000000..4ba79c1 --- /dev/null +++ b/.github/workflows/lint-pr-title.yml @@ -0,0 +1,12 @@ +name: Lint PR title + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + lint-pr-title: + uses: launchdarkly/gh-actions/.github/workflows/lint-pr-title.yml@main diff --git a/.github/workflows/manual-publish-docs.yml b/.github/workflows/manual-publish-docs.yml new file mode 100644 index 0000000..73b5d22 --- /dev/null +++ b/.github/workflows/manual-publish-docs.yml @@ -0,0 +1,22 @@ +on: + workflow_dispatch: + +name: Publish Documentation +jobs: + build-publish-docs: + runs-on: ubuntu-latest + permissions: + id-token: write # Needed if using OIDC to get release secrets. + contents: write # Needed in this case to write github pages. + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0 + + - uses: ./.github/actions/build-docs + + - uses: ./.github/actions/publish-docs + with: + token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml new file mode 100644 index 0000000..50fde11 --- /dev/null +++ b/.github/workflows/manual-publish.yml @@ -0,0 +1,49 @@ +name: Publish Package +on: + workflow_dispatch: + inputs: + dry_run: + description: 'Is this a dry run. If so no package will be published.' + type: boolean + required: true + +jobs: + build-publish: + runs-on: ubuntu-latest + # Needed to get tokens during publishing. + permissions: + id-token: write + contents: read + outputs: + gem-hash: ${{ steps.publish.outputs.gem-hash}} + steps: + - uses: actions/checkout@v4 + + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 + name: 'Get rubygems API key' + with: + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + ssm_parameter_pairs: '/production/common/releasing/rubygems/api_key = GEM_HOST_API_KEY' + + - id: build-and-test + name: Build and Test + uses: ./.github/actions/ci + with: + ruby-version: 3.0 + + - id: publish + name: Publish Package + uses: ./.github/actions/publish + with: + dry_run: ${{ inputs.dry_run }} + + release-provenance: + needs: [ 'build-publish' ] + permissions: + actions: read + id-token: write + contents: write + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.build-publish.outputs.gem-hash }}" + upload-assets: ${{ !inputs.dry_run }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..761f15c --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,65 @@ +name: Run Release Please + +on: + push: + branches: + - main + +jobs: + release-package: + runs-on: ubuntu-latest + permissions: + id-token: write # Needed if using OIDC to get release secrets. + contents: write # Contents and pull-requests are for release-please to make releases. + pull-requests: write + outputs: + release-created: ${{ steps.release.outputs.release_created }} + upload-tag-name: ${{ steps.release.outputs.tag_name }} + gem-hash: ${{ steps.publish.outputs.gem-hash}} + steps: + - uses: googleapis/release-please-action@v4 + id: release + + - uses: actions/checkout@v4 + if: ${{ steps.release.outputs.releases_created == 'true' }} + with: + fetch-depth: 0 # If you only need the current version keep this. + + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 + if: ${{ steps.release.outputs.releases_created == 'true' }} + name: 'Get rubygems API key' + with: + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + ssm_parameter_pairs: '/production/common/releasing/rubygems/api_key = GEM_HOST_API_KEY' + + - uses: ./.github/actions/ci + if: ${{ steps.release.outputs.releases_created == 'true' }} + with: + ruby-version: 3.0 + + - uses: ./.github/actions/build-docs + if: ${{ steps.release.outputs.releases_created == 'true' }} + + - uses: ./.github/actions/publish + id: publish + if: ${{ steps.release.outputs.releases_created == 'true' }} + with: + dry_run: false + + - uses: ./.github/actions/publish-docs + if: ${{ steps.release.outputs.releases_created == 'true' }} + with: + token: ${{secrets.GITHUB_TOKEN}} + + release-provenance: + needs: [ 'release-package' ] + if: ${{ needs.release-package.outputs.release-created == 'true' }} + permissions: + actions: read + id-token: write + contents: write + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.release-package.outputs.gem-hash }}" + upload-assets: true + upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..14118d4 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,10 @@ +name: 'Close stale issues and PRs' +on: + workflow_dispatch: + schedule: + # Happen once per day at 1:30 AM + - cron: '30 1 * * *' + +jobs: + sdk-close-stale: + uses: launchdarkly/gh-actions/.github/workflows/sdk-stale.yml@main diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..e18ee07 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.0" +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..c7e9df9 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,12 @@ +{ + "packages": { + ".": { + "release-type": "ruby", + "bump-minor-pre-major": true, + "versioning": "default", + "include-component-in-tag": false, + "include-v-in-tag": false, + "extra-files": ["PROVENANCE.md", "lib/ldclient-ai/version.rb"] + } + } +} From eef0b3fd0f2801673b112fec98a507a7cada2ad2 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Thu, 29 May 2025 14:13:30 +0000 Subject: [PATCH 2/6] add additional files --- .rubocop.yml | 903 ++++++++++++++++++++++++++++++++++++++++++++++++++ docs/Makefile | 26 ++ 2 files changed, 929 insertions(+) create mode 100644 .rubocop.yml create mode 100644 docs/Makefile diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..c07869b --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,903 @@ +require: + - rubocop-performance + - rubocop-rake + - rubocop-rspec + +AllCops: + TargetRubyVersion: 3.0 + Include: + - lib/**/*.rb + - spec/**/*.rb + - contract-tests/**/*.rb + NewCops: disable + +Naming/AccessorMethodName: + Description: Check the naming of accessor methods for get_/set_. + Enabled: false + +Style/AccessModifierDeclarations: + Description: 'Access modifiers should be declared to apply to a group of methods or inline before each method, depending on configuration.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method' + Enabled: false + +Style/Alias: + Description: 'Use alias_method instead of alias.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method' + Enabled: false + +Style/ArrayJoin: + Description: 'Use Array#join instead of Array#*.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#array-join' + Enabled: false + +Style/AsciiComments: + Description: 'Use only ascii symbols in comments.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-comments' + Enabled: false + +Naming/AsciiIdentifiers: + Description: 'Use only ascii symbols in identifiers.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-identifiers' + Enabled: false + +Naming/VariableName: + Description: 'Makes sure that all variables use the configured style, snake_case or camelCase, for their names.' + Enabled: false + +Style/Attr: + Description: 'Checks for uses of Module#attr.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr' + Enabled: false + +Metrics/AbcSize: + Description: 'Checks that the ABC size of methods is not higher than the configured maximum.' + Enabled: false + +Metrics/BlockLength: + Description: 'Checks if the length of a block exceeds some maximum value.' + Enabled: false + +Metrics/BlockNesting: + Description: 'Avoid excessive block nesting' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count' + Enabled: false + +Style/CaseEquality: + Description: 'Avoid explicit use of the case equality operator(===).' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-case-equality' + Enabled: false + +Style/CharacterLiteral: + Description: 'Checks for uses of character literals.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-character-literals' + Enabled: false + +Style/ClassAndModuleChildren: + Description: 'Checks style of children classes and modules.' + Enabled: true + EnforcedStyle: nested + +Metrics/ClassLength: + Description: 'Avoid classes longer than 100 lines of code.' + Enabled: false + +Metrics/ModuleLength: + Description: 'Avoid modules longer than 100 lines of code.' + Enabled: false + +Style/ClassVars: + Description: 'Avoid the use of class variables.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-class-vars' + Enabled: false + +Style/CollectionMethods: + Enabled: true + PreferredMethods: + find: detect + inject: reduce + collect: map + find_all: select + +Style/ColonMethodCall: + Description: 'Do not use :: for method call.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#double-colons' + Enabled: false + +Style/CommentAnnotation: + Description: >- + Checks formatting of special comments + (TODO, FIXME, OPTIMIZE, HACK, REVIEW). + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#annotate-keywords' + Enabled: false + +Metrics/CyclomaticComplexity: + Description: >- + A complexity metric that is strongly correlated to the number + of test cases needed to validate a method. + Enabled: false + +Style/PreferredHashMethods: + Description: 'Checks for use of deprecated Hash methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-key' + Enabled: false + +Style/Documentation: + Description: 'Document classes and non-namespace modules.' + Enabled: false + +Style/DoubleNegation: + Description: 'Checks for uses of double negation (!!).' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-bang-bang' + Enabled: false + +Style/EachWithObject: + Description: 'Prefer `each_with_object` over `inject` or `reduce`.' + Enabled: false + +Style/EmptyLiteral: + Description: 'Prefer literals to Array.new/Hash.new/String.new.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#literal-array-hash' + Enabled: false + +# Checks whether the source file has a utf-8 encoding comment or not +# AutoCorrectEncodingComment must match the regex +# /#.*coding\s?[:=]\s?(?:UTF|utf)-8/ +Style/Encoding: + Enabled: false + +Style/EvenOdd: + Description: 'Favor the use of Fixnum#even? && Fixnum#odd?' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' + Enabled: false + +Naming/FileName: + Description: 'Use snake_case for source file names.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' + Enabled: false + +Lint/FlipFlop: + Description: 'Checks for flip flops' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-flip-flops' + Enabled: false + +Style/FrozenStringLiteralComment: + Description: 'Helps you transition from mutable string literals to frozen string literals.' + Enabled: false + +Style/FormatString: + Description: 'Enforce the use of Kernel#sprintf, Kernel#format or String#%.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#sprintf' + Enabled: false + +Style/GlobalVars: + Description: 'Do not introduce global variables.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#instance-vars' + Reference: 'https://www.zenspider.com/ruby/quickref.html' + Enabled: false + +Style/GuardClause: + Description: 'Check for conditionals that can be replaced with guard clauses' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' + Enabled: false + +Style/IfUnlessModifier: + Description: >- + Favor modifier if/unless usage when you have a + single-line body. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier' + Enabled: false + +Style/IfWithSemicolon: + Description: 'Do not use if x; .... Use the ternary operator instead.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs' + Enabled: false + +Style/InlineComment: + Description: 'Avoid inline comments.' + Enabled: false + +Style/Lambda: + Description: 'Use the new lambda literal syntax for single-line blocks.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#lambda-multi-line' + Enabled: false + +Style/LambdaCall: + Description: 'Use lambda.call(...) instead of lambda.(...).' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc-call' + Enabled: false + +Style/LineEndConcatenation: + Description: >- + Use \ instead of + or << to concatenate two string literals at + line end. + Enabled: false + +Layout/LineLength: + Description: 'Limit lines to 150 characters.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits' + Max: 180 + +Metrics/MethodLength: + Description: 'Avoid methods longer than 10 lines of code.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods' + Enabled: false + +Style/ModuleFunction: + Description: 'Checks for usage of `extend self` in modules.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#module-function' + Enabled: false + +Style/NegatedIf: + Description: >- + Favor unless over if for negative conditions + (or control flow or). + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#unless-for-negatives' + Enabled: true + +Style/NegatedWhile: + Description: 'Favor until over while for negative conditions.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#until-for-negatives' + Enabled: true + +Style/Next: + Description: 'Use `next` to skip iteration instead of a condition at the end.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' + Enabled: false + +Style/NilComparison: + Description: 'Prefer x.nil? to x == nil.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' + Enabled: false + +Style/Not: + Description: 'Use ! instead of not.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bang-not-not' + Enabled: false + +Style/NumericLiterals: + Description: >- + Add underscores to large numeric literals to improve their + readability. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics' + Enabled: false + +Style/OneLineConditional: + Description: >- + Favor the ternary operator(?:) over + if/then/else/end constructs. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#ternary-operator' + Enabled: false + +Naming/BinaryOperatorParameterName: + Description: 'When defining binary operators, name the argument other.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg' + Enabled: false + +Metrics/ParameterLists: + Description: 'Avoid parameter lists longer than three or four parameters.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#too-many-params' + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Style/PercentLiteralDelimiters: + Description: 'Use `%`-literal delimiters consistently' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-literal-braces' + Enabled: false + +Style/PerlBackrefs: + Description: 'Avoid Perl-style regex back references.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers' + Enabled: false + +Naming/PredicateName: + Description: 'Check the names of predicate methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark' + ForbiddenPrefixes: + - is_ + Exclude: + - spec/**/* + +Style/Proc: + Description: 'Use proc instead of Proc.new.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc' + Enabled: false + +Style/RaiseArgs: + Description: 'Checks the arguments passed to raise/fail.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#exception-class-messages' + Enabled: false + +Style/RegexpLiteral: + Description: 'Use / or %r around regular expressions.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-r' + Enabled: false + +Style/SelfAssignment: + Description: >- + Checks for places where self-assignment shorthand should have + been used. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#self-assignment' + Enabled: false + +Style/SingleLineBlockParams: + Description: 'Enforces the names of some block params.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#reduce-blocks' + Enabled: false + +Style/SingleLineMethods: + Description: 'Avoid single-line methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-single-line-methods' + Enabled: false + +Style/SignalException: + Description: 'Checks for proper usage of fail and raise.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#fail-method' + Enabled: false + +Style/SpecialGlobalVars: + Description: 'Avoid Perl-style global variables.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms' + Enabled: false + +Style/StringLiterals: + Description: 'Checks if uses of quotes match the configured preference.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-string-literals' + EnforcedStyle: double_quotes + Enabled: false + +Style/TrailingCommaInArguments: + Description: 'Checks for trailing comma in argument lists.' + StyleGuide: '#no-trailing-params-comma' + Enabled: true + +Style/TrailingCommaInArrayLiteral: + Description: 'Checks for trailing comma in array and hash literals.' + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: + Description: 'Checks for trailing comma in array and hash literals.' + EnforcedStyleForMultiline: comma + +Style/TrivialAccessors: + Description: 'Prefer attr_* methods to trivial readers/writers.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family' + Enabled: false + +Style/VariableInterpolation: + Description: >- + Don't interpolate global, instance and class variables + directly in strings. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#curlies-interpolate' + Enabled: false + +Style/WhenThen: + Description: 'Use when x then ... for one-line cases.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#one-line-cases' + Enabled: false + +Style/WhileUntilModifier: + Description: >- + Favor modifier while/until usage when you have a + single-line body. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier' + Enabled: false + +Style/WordArray: + Description: 'Use %w or %W for arrays of words.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-w' + Enabled: false + +# Layout +Layout/DotPosition: + Description: 'Checks the position of the dot in multi-line method calls.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains' + EnforcedStyle: leading + +Layout/ExtraSpacing: + Description: 'Do not use unnecessary spacing.' + Enabled: true + AllowBeforeTrailingComments: true + +Layout/MultilineOperationIndentation: + Description: >- + Checks indentation of binary operations that span more than + one line. + Enabled: true + EnforcedStyle: indented + +Layout/InitialIndentation: + Description: >- + Checks the indentation of the first non-blank non-comment line in a file. + Enabled: false + +Layout/SpaceInsideArrayLiteralBrackets: + Description: "Checks that brackets used for array literals have or don't have surrounding space depending on configuration." + Enabled: false + +Layout/TrailingWhitespace: + Description: "Ensures all trailing whitespace has been removed" + Enabled: true + +# Lint + +Lint/AmbiguousOperator: + Description: >- + Checks for ambiguous operators in the first argument of a + method invocation without parentheses. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-as-args' + Enabled: false + +Lint/AmbiguousRegexpLiteral: + Description: >- + Checks for ambiguous regexp literals in the first argument of + a method invocation without parenthesis. + Enabled: false + +Lint/AssignmentInCondition: + Description: "Don't use assignment in conditions." + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition' + Enabled: false + +Lint/CircularArgumentReference: + Description: "Don't refer to the keyword argument in the default value." + Enabled: false + +Layout/ConditionPosition: + Description: >- + Checks for condition placed in a confusing position relative to + the keyword. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#same-line-condition' + Enabled: false + +Lint/DeprecatedClassMethods: + Description: 'Check for deprecated class method calls.' + Enabled: false + +Lint/DuplicateHashKey: + Description: 'Check for duplicate keys in hash literals.' + Enabled: false + +Lint/EachWithObjectArgument: + Description: 'Check for immutable argument given to each_with_object.' + Enabled: false + +Lint/ElseLayout: + Description: 'Check for odd code arrangement in an else block.' + Enabled: false + +Lint/FormatParameterMismatch: + Description: 'The number of parameters to format/sprint must match the fields.' + Enabled: false + +Lint/SuppressedException: + Description: "Don't suppress exception." + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions' + Enabled: false + +Lint/LiteralAsCondition: + Description: 'Checks of literals used in conditions.' + Enabled: false + +Lint/LiteralInInterpolation: + Description: 'Checks for literals used in interpolation.' + Enabled: false + +Lint/Loop: + Description: >- + Use Kernel#loop with break rather than begin/end/until or + begin/end/while for post-loop tests. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#loop-with-break' + Enabled: false + +Lint/NestedMethodDefinition: + Description: 'Do not use nested method definitions.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-methods' + Enabled: false + +Lint/NonLocalExitFromIterator: + Description: 'Do not use return in iterator to cause non-local exit.' + Enabled: false + +Lint/ParenthesesAsGroupedExpression: + Description: >- + Checks for method calls with a space before the opening + parenthesis. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' + Enabled: false + +Lint/RequireParentheses: + Description: >- + Use parentheses in the method call to avoid confusion + about precedence. + Enabled: false + +Lint/UnderscorePrefixedVariableName: + Description: 'Do not use prefix `_` for a variable that is used.' + Enabled: false + +Lint/RedundantCopDisableDirective: + Description: >- + Checks for rubocop:disable comments that can be removed. + Note: this cop is not disabled when disabling all cops. + It must be explicitly disabled. + Enabled: false + +Lint/Void: + Description: 'Possible use of operator/literal/variable in void context.' + Enabled: false + +# Performance + +Performance/CaseWhenSplat: + Description: >- + Place `when` conditions that use splat at the end + of the list of `when` branches. + Enabled: false + +Performance/Count: + Description: >- + Use `count` instead of `select...size`, `reject...size`, + `select...count`, `reject...count`, `select...length`, + and `reject...length`. + Enabled: false + +Performance/Detect: + Description: >- + Use `detect` instead of `select.first`, `find_all.first`, + `select.last`, and `find_all.last`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code' + Enabled: false + +Performance/FlatMap: + Description: >- + Use `Enumerable#flat_map` + instead of `Enumerable#map...Array#flatten(1)` + or `Enumberable#collect..Array#flatten(1)` + Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' + Enabled: false + +Performance/ReverseEach: + Description: 'Use `reverse_each` instead of `reverse.each`.' + Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code' + Enabled: false + +Style/Sample: + Description: >- + Use `sample` instead of `shuffle.first`, + `shuffle.last`, and `shuffle[Fixnum]`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code' + Enabled: false + +Performance/Size: + Description: >- + Use `size` instead of `count` for counting + the number of elements in `Array` and `Hash`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraycount-vs-arraysize-code' + Enabled: false + +Performance/StringReplacement: + Description: >- + Use `tr` instead of `gsub` when you are replacing the same + number of characters. Use `delete` instead of `gsub` when + you are deleting characters. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code' + Enabled: false + +# Disabled temporarily while we bring code base inline +Layout/ArgumentAlignment: + Enabled: false + +Layout/ArrayAlignment: + Enabled: false + +Layout/BlockEndNewline: + Enabled: false + +Layout/CaseIndentation: + Enabled: false + +Layout/ClosingHeredocIndentation: + Enabled: false + +Layout/ClosingParenthesisIndentation: + Enabled: false + +Layout/CommentIndentation: + Enabled: false + +Layout/ElseAlignment: + Enabled: false + +Layout/EmptyLineAfterGuardClause: + Enabled: false + +Layout/EmptyLineBetweenDefs: + Enabled: false + +Layout/EmptyLines: + Enabled: false + +Layout/EmptyLinesAroundBlockBody: + Enabled: false + +Layout/EmptyLinesAroundMethodBody: + Enabled: false + +Layout/EmptyLinesAroundModuleBody: + Enabled: false + +Layout/EndAlignment: + Enabled: false + +Layout/FirstArgumentIndentation: + Enabled: false + +Layout/FirstHashElementIndentation: + Enabled: false + +Layout/HashAlignment: + Enabled: false + +Layout/HeredocIndentation: + Enabled: false + +Layout/IndentationWidth: + Enabled: false + +Layout/LeadingCommentSpace: + Enabled: false + +Layout/LeadingEmptyLines: + Enabled: false + +Layout/MultilineArrayBraceLayout: + Enabled: false + +Layout/MultilineBlockLayout: + Enabled: false + +Layout/MultilineHashBraceLayout: + Enabled: false + +Layout/MultilineMethodCallBraceLayout: + Enabled: false + +Layout/MultilineMethodCallIndentation: + Enabled: false + +Layout/ParameterAlignment: + Enabled: false + +Layout/SpaceAfterComma: + Enabled: false + +Layout/SpaceAroundBlockParameters: + Enabled: false + +Layout/SpaceAroundEqualsInParameterDefault: + Enabled: false + +Layout/SpaceAroundOperators: + Enabled: false + +Layout/SpaceBeforeBlockBraces: + Enabled: false + +Layout/SpaceBeforeComma: + Enabled: false + +Layout/SpaceInsideBlockBraces: + Enabled: false + +Layout/SpaceInsideHashLiteralBraces: + Enabled: false + +Layout/SpaceInsideReferenceBrackets: + Enabled: false + +Layout/TrailingEmptyLines: + Enabled: false + +Lint/ConstantDefinitionInBlock: + Enabled: false + +Lint/IneffectiveAccessModifier: + Enabled: false + +Lint/MissingCopEnableDirective: + Enabled: false + +Lint/RedundantRequireStatement: + Enabled: false + +Lint/StructNewOverride: + Enabled: false + +Lint/UnusedBlockArgument: + Enabled: false + +Lint/UnusedMethodArgument: + Enabled: false + +Lint/UselessAccessModifier: + Enabled: false + +Lint/UselessAssignment: + Enabled: false + +Lint/UselessMethodDefinition: + Enabled: false + +Naming/BlockParameterName: + Enabled: false + +Naming/HeredocDelimiterNaming: + Enabled: false + +Naming/MethodParameterName: + Enabled: false + +Naming/RescuedExceptionsVariableName: + Enabled: false + +Naming/VariableNumber: + Enabled: false + +Style/AccessorGrouping: + Enabled: false + +Style/AndOr: + Enabled: false + +Style/BlockDelimiters: + Enabled: false + +Style/CaseLikeIf: + Enabled: false + +Style/CombinableLoops: + Enabled: false + +Style/CommentedKeyword: + Enabled: false + +Style/ConditionalAssignment: + Enabled: false + +Style/DefWithParentheses: + Enabled: false + +Style/EmptyElse: + Enabled: false + +Style/EmptyMethod: + Enabled: false + +Style/ExplicitBlockArgument: + Enabled: false + +Style/For: + Enabled: false + +Style/FormatStringToken: + Enabled: false + +Style/GlobalStdStream: + Enabled: false + +Style/HashEachMethods: + Enabled: false + +Style/HashSyntax: + Enabled: false + +Style/InfiniteLoop: + Enabled: false + +Style/InverseMethods: + Enabled: false + +Style/MethodCallWithoutArgsParentheses: + Enabled: false + +Style/MissingRespondToMissing: + Enabled: false + +Style/MultilineIfThen: + Enabled: false + +Style/MultilineTernaryOperator: + Enabled: false + +Style/MultipleComparison: + Enabled: false + +Style/MutableConstant: + Enabled: false + +Style/NumericPredicate: + Enabled: false + +Style/OptionalBooleanParameter: + Enabled: false + +Style/ParallelAssignment: + Enabled: false + +Style/RedundantAssignment: + Enabled: false + +Style/RedundantBegin: + Enabled: false + +Style/RedundantCondition: + Enabled: true + +Style/RedundantException: + Enabled: false + +Style/RedundantFileExtensionInRequire: + Enabled: false + +Style/RedundantParentheses: + Enabled: true + +Style/RedundantRegexpEscape: + Enabled: false + +Style/RedundantReturn: + Enabled: true + +Style/RedundantSelf: + Enabled: false + +Style/RescueStandardError: + Enabled: false + +Style/SafeNavigation: + Enabled: false + +Style/Semicolon: + Enabled: true + AllowAsExpressionSeparator: true + +Style/SlicingWithRange: + Enabled: false + +Style/SoleNestedConditional: + Enabled: false + +Style/StringConcatenation: + Enabled: false + +Style/SymbolArray: + Enabled: false + +Style/SymbolProc: + Enabled: false + +Style/TernaryParentheses: + Enabled: false + +Style/TrailingUnderscoreVariable: + Enabled: false + +Style/WhileUntilDo: + Enabled: false + +Style/ZeroLengthPredicate: + Enabled: false + +RSpec/FilePath: + SpecSuffixOnly: true + +RSpec/ExampleLength: + Enabled: false + +RSpec/MultipleExpectations: + Enabled: false + +RSpec/MultipleMemoizedHelpers: + Enabled: false diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..4dd2d17 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,26 @@ +ifeq ($(LD_RELEASE_VERSION),) +TITLE=LaunchDarkly Ruby AI Library +else +TITLE=LaunchDarkly Ruby AI Library ($(LD_RELEASE_VERSION)) +endif + +.PHONY: dependencies html + +html: dependencies + rm -rf ./build + cd .. && yard doc \ + -o docs/build/html \ + --title "$(TITLE)" \ + --no-private \ + --markup markdown \ + --embed-mixins \ + -r docs/index.md \ + lib/*.rb \ + lib/**/*.rb \ + lib/**/**/*.rb \ + lib/**/**/**/*.rb + rm -f build/html/frames.html + +dependencies: + gem install --conservative yard + gem install --conservative redcarpet # provides Markdown formatting From 43b8b2a74639167381502cc228943fad494329ef Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Tue, 17 Jun 2025 14:37:10 +0000 Subject: [PATCH 3/6] update rubocop --- .rubocop.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index c07869b..cd5defd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,4 @@ -require: +plugins: - rubocop-performance - rubocop-rake - rubocop-rspec @@ -291,7 +291,7 @@ Style/PerlBackrefs: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers' Enabled: false -Naming/PredicateName: +Naming/PredicatePrefix: Description: 'Check the names of predicate methods.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark' ForbiddenPrefixes: @@ -890,8 +890,14 @@ Style/WhileUntilDo: Style/ZeroLengthPredicate: Enabled: false -RSpec/FilePath: - SpecSuffixOnly: true +RSpec/MessageSpies: + EnforcedStyle: receive + +RSpec/SpecFilePathFormat: + Enabled: false + +RSpec/SpecFilePathSuffix: + Enabled: true RSpec/ExampleLength: Enabled: false From 88598bdd897d64819293230141bd5a2c0944a7a2 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Tue, 17 Jun 2025 15:53:01 +0000 Subject: [PATCH 4/6] simplify the publish process --- .github/actions/ci/action.yml | 2 +- .../{manual-publish.yml => publish.yml} | 22 +++++++ .github/workflows/release-please.yml | 58 ++++--------------- docs/Makefile | 4 +- 4 files changed, 35 insertions(+), 51 deletions(-) rename .github/workflows/{manual-publish.yml => publish.yml} (65%) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index 229d7ac..155bb44 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -18,7 +18,7 @@ runs: - name: Run tests shell: bash - run: bundle exec rspec spec $SPEC_TAGS + run: bundle exec rspec spec - name: Run RuboCop shell: bash diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/publish.yml similarity index 65% rename from .github/workflows/manual-publish.yml rename to .github/workflows/publish.yml index 50fde11..f008416 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/publish.yml @@ -1,5 +1,16 @@ name: Publish Package on: + workflow_call: + inputs: + dry_run: + description: 'Is this a dry run. If so no package will be published.' + type: boolean + required: true + tag_name: + description: 'The tag name to use for the provenance file' + type: string + required: true + workflow_dispatch: inputs: dry_run: @@ -31,12 +42,21 @@ jobs: with: ruby-version: 3.0 + - id: build-docs + name: Build docs + uses: ./.github/actions/build-docs + - id: publish name: Publish Package uses: ./.github/actions/publish with: dry_run: ${{ inputs.dry_run }} + - uses: ./.github/actions/publish-docs + if: ${{ steps.release.outputs.releases_created == 'true' }} + with: + token: ${{secrets.GITHUB_TOKEN}} + release-provenance: needs: [ 'build-publish' ] permissions: @@ -47,3 +67,5 @@ jobs: with: base64-subjects: "${{ needs.build-publish.outputs.gem-hash }}" upload-assets: ${{ !inputs.dry_run }} + upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }} + provenance-name: ${{ format('{0}_provenance.intoto.jsonl', inputs.tag_name) }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 761f15c..62a59cc 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -1,4 +1,4 @@ -name: Run Release Please +name: Release Please on: push: @@ -6,60 +6,22 @@ on: - main jobs: - release-package: + release-please: runs-on: ubuntu-latest permissions: - id-token: write # Needed if using OIDC to get release secrets. contents: write # Contents and pull-requests are for release-please to make releases. pull-requests: write outputs: release-created: ${{ steps.release.outputs.release_created }} - upload-tag-name: ${{ steps.release.outputs.tag_name }} - gem-hash: ${{ steps.publish.outputs.gem-hash}} + tag-name: ${{ steps.release.outputs.tag_name }} steps: - uses: googleapis/release-please-action@v4 id: release - - - uses: actions/checkout@v4 - if: ${{ steps.release.outputs.releases_created == 'true' }} - with: - fetch-depth: 0 # If you only need the current version keep this. - - - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 - if: ${{ steps.release.outputs.releases_created == 'true' }} - name: 'Get rubygems API key' - with: - aws_assume_role: ${{ vars.AWS_ROLE_ARN }} - ssm_parameter_pairs: '/production/common/releasing/rubygems/api_key = GEM_HOST_API_KEY' - - - uses: ./.github/actions/ci - if: ${{ steps.release.outputs.releases_created == 'true' }} - with: - ruby-version: 3.0 - - - uses: ./.github/actions/build-docs - if: ${{ steps.release.outputs.releases_created == 'true' }} - - - uses: ./.github/actions/publish - id: publish - if: ${{ steps.release.outputs.releases_created == 'true' }} - with: - dry_run: false - - - uses: ./.github/actions/publish-docs - if: ${{ steps.release.outputs.releases_created == 'true' }} - with: - token: ${{secrets.GITHUB_TOKEN}} - - release-provenance: - needs: [ 'release-package' ] - if: ${{ needs.release-package.outputs.release-created == 'true' }} - permissions: - actions: read - id-token: write - contents: write - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + + release-sdk: + needs: release-please + if: ${{ needs.release-please.outputs.release-created == 'true' }} + uses: ./.github/workflows/publish.yml with: - base64-subjects: "${{ needs.release-package.outputs.gem-hash }}" - upload-assets: true - upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }} + dry_run: false + tag_name: ${{ needs.release-please.outputs.tag-name }} diff --git a/docs/Makefile b/docs/Makefile index 4dd2d17..79967fd 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,7 +1,7 @@ ifeq ($(LD_RELEASE_VERSION),) -TITLE=LaunchDarkly Ruby AI Library +TITLE=LaunchDarkly Ruby Server SDK AI Library else -TITLE=LaunchDarkly Ruby AI Library ($(LD_RELEASE_VERSION)) +TITLE=LaunchDarkly Ruby Server SDK AI Library ($(LD_RELEASE_VERSION)) endif .PHONY: dependencies html From 65c343a5a38f9945f27b5e10a916ab2f2175ebf2 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Tue, 17 Jun 2025 17:10:25 +0000 Subject: [PATCH 5/6] include provenance and additional docs --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 1 - PROVENANCE.md | 43 +++++++++++++++++++++++++++++++++++ Rakefile | 12 ++++++++++ docs/index.md | 7 ++++++ 5 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 PROVENANCE.md create mode 100644 Rakefile create mode 100644 docs/index.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 057d2b9..c25881d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,11 +1,11 @@ name: Run CI on: push: - branches: [ main ] + branches: [ main, 'feat/**' ] paths-ignore: - '**.md' # Do not need to run CI for markdown changes. pull_request: - branches: [ main ] + branches: [ main, 'feat/**' ] paths-ignore: - '**.md' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f008416..5f3466f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -68,4 +68,3 @@ jobs: base64-subjects: "${{ needs.build-publish.outputs.gem-hash }}" upload-assets: ${{ !inputs.dry_run }} upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }} - provenance-name: ${{ format('{0}_provenance.intoto.jsonl', inputs.tag_name) }} diff --git a/PROVENANCE.md b/PROVENANCE.md new file mode 100644 index 0000000..b91e010 --- /dev/null +++ b/PROVENANCE.md @@ -0,0 +1,43 @@ +## Verifying SDK build provenance with the SLSA framework + +LaunchDarkly uses the [SLSA framework](https://slsa.dev/spec/v1.0/about) (Supply-chain Levels for Software Artifacts) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages. + +As part of [SLSA requirements for level 3 compliance](https://slsa.dev/spec/v1.0/requirements), LaunchDarkly publishes provenance about our SDK package builds using [GitHub's generic SLSA3 provenance generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md#generation-of-slsa3-provenance-for-arbitrary-projects) for distribution alongside our packages. These attestations are available for download from the GitHub release page for the release version under Assets > `multiple-provenance.intoto.jsonl`. + +To verify SLSA provenance attestations, we recommend using [slsa-verifier](https://github.com/slsa-framework/slsa-verifier). Example usage for verifying SDK packages is included below: + + +``` +# Set the version of the SDK to verify +VERSION=0.0.0 +``` + + +``` +# Download gem +$ gem fetch launchdarkly-server-sdk-ai -v $VERSION + +# Download provenance from Github release +$ curl --location -O \ + https://github.com/launchdarkly/ruby-server-sdk-ai/releases/download/${VERSION}/launchdarkly-server-sdk-ai-${VERSION}.gem.intoto.jsonl + +# Run slsa-verifier to verify provenance against package artifacts +$ slsa-verifier verify-artifact \ +--provenance-path launchdarkly-server-sdk-ai-${VERSION}.gem.intoto.jsonl \ +--source-uri github.com/launchdarkly/ruby-server-sdk-ai \ +launchdarkly-server-sdk-ai-${VERSION}.gem +``` + +Below is a sample of expected output. +TODO: Verify these are accurate +``` +Verified signature against tlog entry index 83653185 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a7df0bbf87a7d5fcaafa551a2101d9f993d251a56a918bb113e81d2c575dc7e25 +Verified build using builder "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.10.0" at commit 14c48a68c45871c27409591969e7f4c0ebdcdf62 +Verifying artifact launchdarkly-server-sdk-ai-1.0.0.gem: PASSED + +PASSED: Verified SLSA provenance +``` + +Alternatively, to verify the provenance manually, the SLSA framework specifies [recommendations for verifying build artifacts](https://slsa.dev/spec/v1.0/verifying-artifacts) in their documentation. + +**Note:** These instructions do not apply when building our libraries from source. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..cca7175 --- /dev/null +++ b/Rakefile @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +require "rubocop/rake_task" + +RuboCop::RakeTask.new + +task default: %i[spec rubocop] diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..b351a20 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,7 @@ +# LaunchDarkly Server-side AI library for Ruby + +This generated API documentation lists all types and methods in the SDK. + +The API documentation for the most recent release is hosted on [GitHub Pages](https://launchdarkly.github.io/ruby-server-sdk-ai). API documentation for current and past releases is hosted on [RubyDoc.info](https://www.rubydoc.info/gems/launchdarkly-server-sdk-ai). + +Source code and readme: [GitHub](https://github.com/launchdarkly/ruby-server-sdk-ai) From bb97e3f2760e7f7eb31fa2b3719ca3ff0aecbfac Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Tue, 17 Jun 2025 17:14:39 +0000 Subject: [PATCH 6/6] remove debug dependency --- launchdarkly-server-sdk-ai.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/launchdarkly-server-sdk-ai.gemspec b/launchdarkly-server-sdk-ai.gemspec index fba31a0..ff31591 100644 --- a/launchdarkly-server-sdk-ai.gemspec +++ b/launchdarkly-server-sdk-ai.gemspec @@ -24,7 +24,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'mustache', '~> 1.1' spec.add_development_dependency 'bundler', '~> 2.0' - spec.add_development_dependency 'debug', '~> 1.0' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec', '~> 3.0' spec.add_development_dependency 'rubocop', '~> 1.21'