Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Infisical/sdk
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.1.0
Choose a base ref
...
head repository: Infisical/sdk
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Jan 18, 2024

  1. Clean up access_token

    rustaceanrob committed Jan 18, 2024
    Copy the full SHA
    05fbdce View commit details

Commits on Jan 24, 2024

  1. Update release-python.yml

    DanielHougaard committed Jan 24, 2024
    Copy the full SHA
    f123e75 View commit details
  2. Update settings.json

    DanielHougaard committed Jan 24, 2024
    Copy the full SHA
    ef14187 View commit details
  3. Copy the full SHA
    157cc71 View commit details
  4. Copy the full SHA
    bce77da View commit details
  5. Copy the full SHA
    775a7ca View commit details
  6. Copy the full SHA
    462958c View commit details
  7. Copy the full SHA
    9534c64 View commit details
  8. Update .gitignore

    DanielHougaard committed Jan 24, 2024
    Copy the full SHA
    4c46f9b View commit details
  9. Merge pull request #21 from Infisical/daniel/fixes

    (Fix): Python process hanging & schema issue, .NET attach to process env
    DanielHougaard authored Jan 24, 2024
    Copy the full SHA
    c84056c View commit details

Commits on Jan 26, 2024

  1. Update infisical_client.py

    DanielHougaard committed Jan 26, 2024
    Copy the full SHA
    e47608e View commit details

Commits on Jan 29, 2024

  1. Update env_logger (python)

    DanielHougaard committed Jan 29, 2024
    Copy the full SHA
    051aae0 View commit details
  2. Update Cargo.toml

    DanielHougaard committed Jan 29, 2024
    Copy the full SHA
    2ac1dca View commit details

Commits on Jan 30, 2024

  1. Potential fix for certificate issue

    DanielHougaard committed Jan 30, 2024
    Copy the full SHA
    15b50f0 View commit details
  2. Another possible fix for certificate issue

    DanielHougaard committed Jan 30, 2024
    Copy the full SHA
    70ccd61 View commit details
  3. Vendored OpenSSL

    DanielHougaard committed Jan 30, 2024
    Copy the full SHA
    073b135 View commit details
  4. More vendored

    DanielHougaard committed Jan 30, 2024
    Copy the full SHA
    d74e45d View commit details
  5. Rust TLS config

    DanielHougaard committed Jan 30, 2024
    Copy the full SHA
    023fcf5 View commit details

Commits on Feb 1, 2024

  1. New Python CI

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    e16af1a View commit details
  2. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    a7bf95e View commit details
  3. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    c1534bb View commit details
  4. Update build-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    e99258a View commit details
  5. for testing

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    948a000 View commit details
  6. Update build-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    61bfd5b View commit details
  7. Update build-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    82e0f14 View commit details
  8. Update build-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    5c4e1a0 View commit details
  9. Update build-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    5ae212b View commit details
  10. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    0b085f8 View commit details
  11. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    a18c8eb View commit details
  12. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    667f3ae View commit details
  13. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    3b4600c View commit details
  14. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    52312e9 View commit details
  15. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    3926085 View commit details
  16. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    9d04310 View commit details
  17. Final

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    384caaf View commit details
  18. Update release-python.yml

    DanielHougaard committed Feb 1, 2024
    Copy the full SHA
    e32d733 View commit details
  19. Merge pull request #25 from Infisical/python-test

    (Fix): Refactor Python CI
    DanielHougaard authored Feb 1, 2024
    Copy the full SHA
    57a3725 View commit details
  20. Copy the full SHA
    27022df View commit details

Commits on Mar 3, 2024

  1. Merge pull request #17 from rustaceanrob/access-token-strings

    Clean up access_token
    DanielHougaard authored Mar 3, 2024
    Copy the full SHA
    6c58234 View commit details

Commits on Apr 15, 2024

  1. Copy the full SHA
    56395a5 View commit details
  2. Removed more unused packages

    DanielHougaard committed Apr 15, 2024
    Copy the full SHA
    a65147b View commit details

Commits on May 17, 2024

  1. Copy the full SHA
    228d9f3 View commit details
  2. Delete access_token.rs

    DanielHougaard committed May 17, 2024
    Copy the full SHA
    2a3d407 View commit details
  3. Update mod.rs

    DanielHougaard committed May 17, 2024
    Copy the full SHA
    855f3af View commit details
  4. Feat: UA login fixes

    DanielHougaard committed May 17, 2024
    Copy the full SHA
    cfb838e View commit details
  5. Update authenticate.rs

    DanielHougaard committed May 17, 2024
    Copy the full SHA
    fdb401b View commit details
  6. Update mod.rs

    DanielHougaard committed May 17, 2024
    Copy the full SHA
    6526458 View commit details
  7. Copy the full SHA
    5fa514e View commit details
  8. Copy the full SHA
    aeff53a View commit details
  9. Feat: auth parameter

    DanielHougaard committed May 17, 2024
    Copy the full SHA
    750ab93 View commit details
Showing with 4,408 additions and 2,219 deletions.
  1. +322 −0 .github/disabled-workflows/release-python.yml
  2. +39 −5 .github/workflows/build-c-bindings.yml
  3. +7 −8 .github/workflows/build-napi.yml
  4. +183 −0 .github/workflows/build-python.yml
  5. +7 −0 .github/workflows/generate-schemas.yml
  6. +5 −0 .github/workflows/release-dotnet.yml
  7. +55 −5 .github/workflows/release-java.yml
  8. +10 −0 .github/workflows/release-node.yml
  9. +41 −268 .github/workflows/release-python.yml
  10. +118 −0 .github/workflows/release-ruby.yml
  11. +13 −5 .github/workflows/rust-test.yml
  12. +13 −1 .gitignore
  13. +2 −0 .vscode/settings.json
  14. +14 −0 crates/infisical-json/src/client.rs
  15. +12 −0 crates/infisical-json/src/command.rs
  16. +2 −1 crates/infisical-py/Cargo.toml
  17. +12 −1 crates/infisical-py/infisical_client/__init__.py
  18. +10 −7 crates/infisical-py/infisical_client/infisical_client.py
  19. BIN crates/infisical-py/infisical_client/infisical_py.cpython-312-darwin.so
  20. +9 −2 crates/infisical-py/src/client.rs
  21. +9 −3 crates/infisical/Cargo.toml
  22. +0 −57 crates/infisical/src/api/access_token.rs
  23. +109 −0 crates/infisical/src/api/auth/aws_iam_login.rs
  24. +47 −0 crates/infisical/src/api/auth/azure_login.rs
  25. +123 −0 crates/infisical/src/api/auth/gcp_iam_login.rs
  26. +50 −0 crates/infisical/src/api/auth/gcp_id_token_login.rs
  27. +42 −0 crates/infisical/src/api/auth/kubernetes_login.rs
  28. +126 −0 crates/infisical/src/api/auth/mod.rs
  29. +42 −0 crates/infisical/src/api/auth/universal_auth_login.rs
  30. +1 −1 crates/infisical/src/api/mod.rs
  31. +3 −7 crates/infisical/src/api/secrets/create_secret.rs
  32. +3 −7 crates/infisical/src/api/secrets/delete_secret.rs
  33. +23 −12 crates/infisical/src/api/secrets/get_secret.rs
  34. +34 −25 crates/infisical/src/api/secrets/list_secrets.rs
  35. +3 −7 crates/infisical/src/api/secrets/update_secret.rs
  36. +0 −25 crates/infisical/src/auth/authenticate.rs
  37. +1 −4 crates/infisical/src/auth/mod.rs
  38. +19 −5 crates/infisical/src/cache.rs
  39. +269 −0 crates/infisical/src/client/auth_method_settings.rs
  40. +29 −18 crates/infisical/src/client/client.rs
  41. +37 −2 crates/infisical/src/client/client_settings.rs
  42. +1 −0 crates/infisical/src/client/mod.rs
  43. +35 −0 crates/infisical/src/constants.rs
  44. +51 −3 crates/infisical/src/error.rs
  45. +305 −20 crates/infisical/src/helper.rs
  46. +1 −1 crates/infisical/src/lib.rs
  47. +11 −0 crates/infisical/src/manager/auth/aws_iam.rs
  48. +11 −0 crates/infisical/src/manager/auth/azure.rs
  49. +16 −0 crates/infisical/src/manager/auth/gcp_iam.rs
  50. +11 −0 crates/infisical/src/manager/auth/gcp_id_token.rs
  51. +19 −0 crates/infisical/src/manager/auth/kubernetes.rs
  52. +6 −0 crates/infisical/src/manager/auth/mod.rs
  53. +12 −0 crates/infisical/src/manager/auth/universal_auth.rs
  54. +94 −0 crates/infisical/src/manager/client_auth.rs
  55. +2 −0 crates/infisical/src/manager/mod.rs
  56. +1 −2 crates/infisical/src/manager/secrets/get.rs
  57. +2 −0 crates/infisical/src/manager/secrets/list.rs
  58. +5 −0 crates/infisical/src/manager/secrets/mod.rs
  59. +26 −3 crates/infisical/tests/cryptography.rs
  60. +17 −1 crates/infisical/tests/secrets.rs
  61. +70 −0 languages/csharp/Infisical.Sdk/DateTimeTypeForwarding.cs
  62. +18 −1 languages/csharp/Infisical.Sdk/Infisical.Sdk.csproj
  63. +13 −0 languages/csharp/Infisical.Sdk/InfisicalClient.cs
  64. +49 −28 languages/java/build.gradle
  65. +22 −15 languages/java/src/main/java/com/infisical/sdk/Example.java
  66. +44 −1 languages/java/src/main/java/com/infisical/sdk/InfisicalClient.java
  67. +610 −12 languages/node/README.md
  68. +116 −111 languages/node/examples/secrets.ts
  69. +2 −4 languages/node/package.json
  70. +91 −0 languages/ruby/examples/basic.rb
  71. +12 −0 languages/ruby/infisical-sdk/Gemfile
  72. +11 −0 languages/ruby/infisical-sdk/Rakefile
  73. +46 −0 languages/ruby/infisical-sdk/Steepfile
  74. +49 −0 languages/ruby/infisical-sdk/infisical-sdk.gemspec
  75. +100 −0 languages/ruby/infisical-sdk/lib/clients/auth.rb
  76. +90 −0 languages/ruby/infisical-sdk/lib/clients/cryptography.rb
  77. +171 −0 languages/ruby/infisical-sdk/lib/clients/secrets.rb
  78. +16 −0 languages/ruby/infisical-sdk/lib/command_runner.rb
  79. +38 −0 languages/ruby/infisical-sdk/lib/extended_schemas/schemas.rb
  80. +45 −0 languages/ruby/infisical-sdk/lib/infisical-sdk.rb
  81. +10 −0 languages/ruby/infisical-sdk/lib/infisical_error.rb
  82. +44 −0 languages/ruby/infisical-sdk/lib/infisical_lib.rb
  83. +5 −0 languages/ruby/infisical-sdk/lib/version.rb
  84. +20 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/auth_client.rbs
  85. +10 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/command_runner.rbs
  86. +15 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/cryptography_client.rbs
  87. +30 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/infisical_client.rbs
  88. +7 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/infisical_lib.rbs
  89. +3 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/sdk.rbs
  90. +56 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/secrets_client.rbs
  91. +37 −0 languages/ruby/infisical-sdk/sig/infisical_sdk/structs.rbs
  92. +0 −1 package.json
  93. +73 −66 support/scripts/schemas.ts
  94. +15 −1,474 yarn.lock
322 changes: 322 additions & 0 deletions .github/disabled-workflows/release-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
name: Release Python SDK
run-name: Release Python SDK

on:
push:
tags:
- "*.*.*"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.sha }}
cancel-in-progress: true

permissions:
contents: write
packages: write

jobs:
generate_schemas:
uses: ./.github/workflows/generate-schemas.yml

test-rust-crate:
uses: ./.github/workflows/rust-test.yml

bump-version:
name: Version changes
needs:
- generate_schemas
- test-rust-crate
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Install python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Bump versions (pyproject.toml / Cargo.toml)
run: |
cd ./crates/infisical-py
pip install poetry
poetry self add poetry-bumpversion
poetry version ${{ github.ref_name }}
cd ../..
- name: Upload Cargo.toml artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: Cargo.toml
path: ./crates/infisical-py/Cargo.toml
- name: Upload pyproject.toml artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: pyproject.toml
path: ./crates/infisical-py/pyproject.toml

- name: Upload __init__.py artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/__init__.py

linux:
runs-on: ubuntu-20.04
needs:
- bump-version
- sdist
strategy:
matrix:
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le]
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Delete existing version files
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

- name: Retrieve Type Definitions
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.py
path: ${{ github.workspace }}/crates/infisical-py/infisical_client/

#sudo apt install libssl-dev
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev
sudo apt-get install -y pkg-config
- name: Build wheels
uses: PyO3/maturin-action@v1
env:
# Make psm compile, see https://github.com/rust-lang/stacker/issues/79
CFLAGS_s390x_unknown_linux_gnu: "-march=z10"
# Workaround ring 0.17 build issue
CFLAGS_aarch64_unknown_linux_gnu: "-D__ARM_ARCH=8"
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --verbose --manifest-path ./crates/infisical-py/Cargo.toml
sccache: "true"
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist

windows:
runs-on: windows-latest
needs:
- bump-version
- generate_schemas
- sdist
strategy:
matrix:
target: [x64, x86]
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Delete existing version files
run: |
del ./crates/infisical-py/Cargo.toml
del ./crates/infisical-py/pyproject.toml
del ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

- name: Retrieve Type Definitions
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.py
path: ${{ github.workspace }}/crates/infisical-py/infisical_client/

- uses: actions/setup-python@v4
with:
python-version: "3.10"
architecture: ${{ matrix.target }}

- uses: dtolnay/rust-toolchain@stable
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --verbose --manifest-path ./crates/infisical-py/Cargo.toml
sccache: "true"
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
macos:
runs-on: macos-latest
needs:
- bump-version
- generate_schemas
- sdist
strategy:
matrix:
target: [aarch64, x86_64]
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Delete existing version files
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

- name: Retrieve Type Definitions
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.py
path: ${{ github.workspace }}/crates/infisical-py/infisical_client/

- uses: actions/setup-python@v4
with:
python-version: "3.10"
- uses: dtolnay/rust-toolchain@stable
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --verbose --manifest-path ./crates/infisical-py/Cargo.toml
sccache: "true"
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist

sdist:
runs-on: ubuntu-latest
needs:
- bump-version
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Delete existing version files
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

- name: Retrieve Type Definitions
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.py
path: ${{ github.workspace }}/crates/infisical-py/infisical_client/

- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist --manifest-path ./crates/infisical-py/Cargo.toml
- name: Upload sdist
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist

release:
name: Release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
# linux, windows
needs: [sdist, macos, linux, windows]
steps:
- uses: actions/download-artifact@v3
with:
name: wheels
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
with:
command: upload
args: --skip-existing *
44 changes: 39 additions & 5 deletions .github/workflows/build-c-bindings.yml
Original file line number Diff line number Diff line change
@@ -19,6 +19,12 @@ jobs:
target: x86_64-pc-windows-msvc
- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu
- os: ubuntu-22.04
target: aarch64-unknown-linux-gnu
- os: ubuntu-22.04
target: aarch64-unknown-linux-musl
- os: ubuntu-22.04
target: x86_64-unknown-linux-musl

steps:
- name: Checkout
@@ -35,14 +41,42 @@ jobs:
- name: Add build architecture
run: rustup target add ${{ matrix.settings.target }}

- name: Build Rust
- name: Install cross-compilation tools for aarch64-gnu
if: matrix.settings.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- uses: goto-bus-stop/setup-zig@7ab2955eb728f5440978d5824358023be3a2802d # v2.2.0
if: ${{ contains(matrix.settings.target, 'musl') }}
with:
version: 0.12.0

- name: Install Zigbuild
if: ${{ contains(matrix.settings.target, 'musl') }}
run: cargo install cargo-zigbuild --locked --git https://github.com/rust-cross/cargo-zigbuild --rev 6f7e1336c9cd13cf1b3704f93c40fcf84caaed6b # 0.18.4

- name: Add build architecture
run: rustup target add ${{ matrix.settings.target }}

- name: Build Rust for MUSL - ${{ matrix.settings.target }}
if: ${{ contains(matrix.settings.target, 'musl') }}
env:
RUSTFLAGS: "-D warnings -C target-feature=-crt-static"
run: cargo zigbuild -p infisical-c --target ${{ matrix.settings.target }} --release

- name: Build Rust for Non-MUSL - ${{ matrix.settings.target }}
if: ${{ !contains(matrix.settings.target, 'musl') }}
env:
RUSTFLAGS: "-D warnings"
run: cargo build --target ${{ matrix.settings.target }} --release --workspace --exclude infisical-py # We have to exclude python due to a bug in pyo3 causing the build to fail on macos. We don't need the python bindings for the CI anyways.
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
RUSTFLAGS: "-D warnings -C target-feature=-crt-static"
run: cargo build -p infisical-c --target ${{ matrix.settings.target }} --release

- name: Upload Artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: libinfisical_c_files-${{ matrix.settings.target }}
path: |
target/${{ matrix.settings.target }}/release/*infisical_c*
path: | # .so for linux, .dll for windows, .dylib for darwin/macos
target/${{ matrix.settings.target }}/release/*infisical_c*.so
target/${{ matrix.settings.target }}/release/*infisical_c*.dll
target/${{ matrix.settings.target }}/release/*infisical_c*.dylib
15 changes: 7 additions & 8 deletions .github/workflows/build-napi.yml
Original file line number Diff line number Diff line change
@@ -7,10 +7,13 @@ env:
permissions:
contents: write
id-token: write
"on":

on:
#push:
# branches:
# - "test-workflows"
# branches:
# - "daniel/fix-x64-darwin-release"
#workflow_dispatch:

workflow_call:

defaults:
@@ -23,18 +26,14 @@ jobs:
name: Generate schemas
uses: ./.github/workflows/generate-schemas.yml

test-rust-crate:
uses: ./.github/workflows/rust-test.yml

build:
needs:
- generate_schemas
- test-rust-crate
strategy:
fail-fast: false
matrix:
settings:
- os: macos-latest
- os: macos-14-large
target: x86_64-apple-darwin
build: |
yarn build && yarn post-build
183 changes: 183 additions & 0 deletions .github/workflows/build-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
name: Build Python

on:
workflow_call:
workflow_dispatch:

jobs:
generate_schemas:
uses: ./.github/workflows/generate-schemas.yml

bump-version:
name: Version changes
needs:
- generate_schemas
runs-on: ubuntu-latest
# if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Install python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Bump versions (pyproject.toml / Cargo.toml)
run: | # poetry version ${{ github.ref_name }}
cd ./crates/infisical-py
pip install poetry
poetry self add poetry-bumpversion
poetry version ${{ github.ref_name }}
cd ../..
- name: Upload Cargo.toml artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: Cargo.toml
path: ./crates/infisical-py/Cargo.toml
- name: Upload pyproject.toml artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: pyproject.toml
path: ./crates/infisical-py/pyproject.toml

- name: Upload __init__.py artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/__init__.py

setup:
name: Setup
runs-on: ubuntu-22.04
steps:
- name: Checkout repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

build:
name: Building Python wheel for - ${{ matrix.settings.os }} - ${{ matrix.settings.target }}
runs-on: ${{ matrix.settings.os || 'ubuntu-latest' }}
needs:
- generate_schemas
- bump-version
- setup
env:
_PACKAGE_VERSION: ${{ github.ref_name }}
# _PACKAGE_VERSION: "2.1.8"
strategy:
fail-fast: false
matrix:
settings:
- os: macos-12
target: x86_64-apple-darwin

- os: macos-12
target: aarch64-apple-darwin

- os: windows-2022
target: x86_64-pc-windows-msvc

- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu

- os: ubuntu-22.04
target: aarch64-unknown-linux-gnu

steps:
- name: Checkout repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Setup Node
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version: 18

- name: Install rust
uses: dtolnay/rust-toolchain@be73d7920c329f220ce78e0234b8f96b7ae60248 # stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}

- name: Cache cargo registry
uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3
with:
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.os }}

# Deleting old files that contain versioning info, and replacing them with our modified artifacts.

- name: Delete existing version files (Linux/MacOS)
if: ${{ matrix.settings.os != 'windows-2022' }}
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Delete existing version files (Windows)
if: ${{ matrix.settings.os == 'windows-2022' }}
run: |
del .\crates\infisical-py\Cargo.toml
del .\crates\infisical-py\pyproject.toml
del .\crates\infisical-py\infisical_client\__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

# End of file replacement

- name: Retrieve Type Definitions
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.py
path: ${{ github.workspace }}/crates/infisical-py/infisical_client/

- name: Build wheels
if: ${{ matrix.settings.target != 'x86_64-unknown-linux-gnu' }}
uses: PyO3/maturin-action@a3013db91b2ef2e51420cfe99ee619c8e72a17e6 # v1.40.8
with:
target: ${{ matrix.settings.target }}
args: --release --find-interpreter --sdist
sccache: "true"
manylinux: "2_28" # https://github.com/pola-rs/polars/pull/12211
working-directory: ${{ github.workspace }}/crates/infisical-py

- name: Build wheels (Linux - x86_64)
if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }}
uses: PyO3/maturin-action@a3013db91b2ef2e51420cfe99ee619c8e72a17e6 # v1.40.8
with:
target: ${{ matrix.settings.target }}
args: --release --find-interpreter --sdist
container: quay.io/pypa/manylinux_2_28_x86_64:2023-11-20-745eb52
sccache: "true"
manylinux: "2_28" # https://github.com/pola-rs/polars/pull/12211
working-directory: ${{ github.workspace }}/crates/infisical-py

- name: Upload wheels
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
with:
name: infisical_python-${{ env._PACKAGE_VERSION }}-${{ matrix.settings.target }}
path: ${{ github.workspace }}/target/wheels/infisical_python*.whl

- name: Upload sdists
if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }} # we only need one sdist
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
with:
name: infisical_python-${{ env._PACKAGE_VERSION }}-sdist
path: ${{ github.workspace }}/target/wheels/infisical_python-*.tar.gz
7 changes: 7 additions & 0 deletions .github/workflows/generate-schemas.yml
Original file line number Diff line number Diff line change
@@ -77,3 +77,10 @@ jobs:
name: sdk-schemas-java
path: ${{ github.workspace }}/languages/java/src/main/java/com/infisical/sdk/schema/*
if-no-files-found: error

- name: Upload Ruby schemas artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: sdk-schemas-ruby
path: ${{ github.workspace }}/languages/ruby/infisical-sdk/lib/schemas.rb
if-no-files-found: error
5 changes: 5 additions & 0 deletions .github/workflows/release-dotnet.yml
Original file line number Diff line number Diff line change
@@ -15,6 +15,11 @@ jobs:

test-rust-crate:
uses: ./.github/workflows/rust-test.yml
secrets:
INFISICAL_UNIVERSAL_CLIENT_SECRET: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_SECRET }}
INFISICAL_UNIVERSAL_CLIENT_ID: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_ID }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}

build_dotnet:
name: Build .NET
60 changes: 55 additions & 5 deletions .github/workflows/release-java.yml
Original file line number Diff line number Diff line change
@@ -15,6 +15,11 @@ jobs:

test-rust-crate:
uses: ./.github/workflows/rust-test.yml
secrets:
INFISICAL_UNIVERSAL_CLIENT_SECRET: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_SECRET }}
INFISICAL_UNIVERSAL_CLIENT_ID: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_ID }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}

build_java:
name: Build Java
@@ -40,34 +45,79 @@ jobs:
distribution: temurin
java-version: 21

# x86/x64 GNU bindings (MacOS)
- name: Download x86_64-apple-darwin files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-apple-darwin
path: languages/java/src/main/resources/darwin-x86-64

# Aarch64 GNU bindings (MacOS)
- name: Download aarch64-apple-darwin files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-aarch64-apple-darwin
path: languages/java/src/main/resources/darwin-aarch64

# x86/x64 GNU bindings (LINUX)
- name: Download x86_64-unknown-linux-gnu files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-unknown-linux-gnu
path: languages/java/src/main/resources/linux-x86-64

# Aarch64 GNU bindings (LINUX)
- name: Download aarch64-unknown-linux-gnu files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-aarch64-unknown-linux-gnu
path: languages/java/src/main/resources/linux-aarch64-gnu

# Aarch64 Musl bindings (LINUX)
- name: Download aarch64-unknown-linux-musl files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-aarch64-unknown-linux-musl
path: languages/java/src/main/resources/linux-aarch64-musl

# x86/x64 Musl bindings (LINUX)
- name: Download x86_64-unknown-linux-musl files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-unknown-linux-musl
path: languages/java/src/main/resources/linux-x86-64-musl

# x86/x64 Musl bindings (Windows)
- name: Download x86_64-pc-windows-msvc files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-pc-windows-msvc
path: languages/java/src/main/resources/win32-x86-64

- name: Organize and rename Linux ARM64 libraries
run: |
mkdir -p languages/java/src/main/resources/linux-aarch64
mv languages/java/src/main/resources/linux-aarch64-gnu/libinfisical_c.so languages/java/src/main/resources/linux-aarch64/libinfisical_c_aarch64_gnu.so
mv languages/java/src/main/resources/linux-aarch64-musl/libinfisical_c.so languages/java/src/main/resources/linux-aarch64/libinfisical_c_aarch64_musl.so
mv languages/java/src/main/resources/linux-x86-64-musl/libinfisical_c.so languages/java/src/main/resources/linux-x86-64/libinfisical_c_x64_musl.so
rm -rf languages/java/src/main/resources/linux-aarch64-musl
rm -rf languages/java/src/main/resources/linux-x86-64-musl
rm -rf languages/java/src/main/resources/linux-aarch64-gnu
- name: List files in resources folders
run: |
echo "Listing files in languages/java/src/main/resources:"
ls -R languages/java/src/main/resources
- name: Publish Maven
uses: gradle/gradle-build-action@b5126f31dbc19dd434c3269bf8c28c315e121da2 # v2.8.1
with:
arguments: publish
build-root-directory: languages/java
working-directory: languages/java
run: |
./gradlew publishAndReleaseToMavenCentral --no-configuration-cache
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALUSERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALPASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEYID }} # Last 8 characters of the full key ID
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEYPASSWORD }}
10 changes: 10 additions & 0 deletions .github/workflows/release-node.yml
Original file line number Diff line number Diff line change
@@ -16,7 +16,17 @@ jobs:
build-napi:
uses: ./.github/workflows/build-napi.yml

test-rust-crate:
uses: ./.github/workflows/rust-test.yml
secrets:
INFISICAL_UNIVERSAL_CLIENT_SECRET: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_SECRET }}
INFISICAL_UNIVERSAL_CLIENT_ID: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_ID }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}

setup:
needs:
- test-rust-crate
name: Setup
runs-on: ubuntu-22.04
steps:
309 changes: 41 additions & 268 deletions .github/workflows/release-python.yml
Original file line number Diff line number Diff line change
@@ -1,297 +1,70 @@
---
name: Release Python SDK
run-name: Release Python SDK

on:
push:
tags:
- "*.*.*"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.sha }}
cancel-in-progress: true

permissions:
contents: write
packages: write
- "*.*.*" # version, e.g. 1.0.0

jobs:
generate_schemas:
uses: ./.github/workflows/generate-schemas.yml
build-python:
uses: ./.github/workflows/build-python.yml

test-rust-crate:
uses: ./.github/workflows/rust-test.yml
secrets:
INFISICAL_UNIVERSAL_CLIENT_SECRET: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_SECRET }}
INFISICAL_UNIVERSAL_CLIENT_ID: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_ID }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}

bump-version:
name: Version changes
setup:
needs:
- generate_schemas
- test-rust-crate
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Install python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Bump versions (pyproject.toml / Cargo.toml)
run: |
cd ./crates/infisical-py
pip install poetry
poetry self add poetry-bumpversion
poetry version ${{ github.ref_name }}
cd ../..
- name: Upload Cargo.toml artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: Cargo.toml
path: ./crates/infisical-py/Cargo.toml
- name: Upload pyproject.toml artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: pyproject.toml
path: ./crates/infisical-py/pyproject.toml

- name: Upload __init__.py artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/__init__.py

linux:
runs-on: ubuntu-20.04
needs:
- bump-version
- sdist
strategy:
matrix:
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le]
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Delete existing version files
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

- name: Retrieve Type Definitions
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: schemas.py
path: ${{ github.workspace }}/crates/infisical-py/infisical_client/

- name: Build wheels
uses: PyO3/maturin-action@v1
env:
# Make psm compile, see https://github.com/rust-lang/stacker/issues/79
CFLAGS_s390x_unknown_linux_gnu: "-march=z10"
# Workaround ring 0.17 build issue
CFLAGS_aarch64_unknown_linux_gnu: "-D__ARM_ARCH=8"
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --verbose --manifest-path ./crates/infisical-py/Cargo.toml
sccache: "true"
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist

windows:
runs-on: windows-latest
needs:
- bump-version
- generate_schemas
- sdist
strategy:
matrix:
target: [x64, x86]
- build-python
name: Setup
runs-on: ubuntu-22.04
steps:
- name: Checkout
- name: Checkout repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Delete existing version files
run: |
del ./crates/infisical-py/Cargo.toml
del ./crates/infisical-py/pyproject.toml
del ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/

- uses: actions/setup-python@v4
with:
python-version: "3.10"
architecture: ${{ matrix.target }}

- uses: dtolnay/rust-toolchain@stable
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --verbose --manifest-path ./crates/infisical-py/Cargo.toml
sccache: "true"
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
macos:
runs-on: macos-latest
publish:
name: Publish
runs-on: ubuntu-22.04
needs:
- bump-version
- generate_schemas
- sdist
strategy:
matrix:
target: [aarch64, x86_64]
- setup
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Delete existing version files
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
- name: Install Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/
python-version: "3.9"

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/
- name: Install twine
run: pip install twine

- uses: actions/setup-python@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
python-version: "3.10"
- uses: dtolnay/rust-toolchain@stable
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --verbose --manifest-path ./crates/infisical-py/Cargo.toml
sccache: "true"
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
path: ${{ github.workspace }}/target/wheels/dist

sdist:
runs-on: ubuntu-latest
needs:
- bump-version
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}
- name: List packages
run: ls -R ./target/wheels/dist
shell: bash

- name: Delete existing version files
- name: Move files
working-directory: ${{ github.workspace }}/target/wheels/dist
run: |
rm -rf ./crates/infisical-py/Cargo.toml
rm -rf ./crates/infisical-py/pyproject.toml
rm -rf ./crates/infisical-py/infisical_client/__init__.py
- name: Download Cargo.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: Cargo.toml
path: ./crates/infisical-py/
- name: Download pyproject.toml artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: pyproject.toml
path: ./crates/infisical-py/

- name: Download __init__.py artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: __init__.py
path: ./crates/infisical-py/infisical_client/
find . -maxdepth 2 -type f -print0 | xargs -0 mv -t .
rm -rf */
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist --manifest-path ./crates/infisical-py/Cargo.toml
- name: Upload sdist
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
- name: Check
working-directory: ${{ github.workspace }}/target/wheels
run: twine check dist/*

release:
name: Release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
# linux, windows
needs: [sdist, macos, linux, windows]
steps:
- uses: actions/download-artifact@v3
with:
name: wheels
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
- name: Publish
working-directory: ${{ github.workspace }}/target/wheels
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
with:
command: upload
args: --skip-existing *
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: twine upload --repository pypi dist/*
118 changes: 118 additions & 0 deletions .github/workflows/release-ruby.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: Release Ruby SDK
run-name: Release Ruby SDK

on:
workflow_dispatch:

push:
tags:
- "*.*.*" # version, e.g. 1.0.0

permissions:
contents: read
id-token: write

jobs:
generate_schemas:
uses: ./.github/workflows/generate-schemas.yml

build_rust:
uses: ./.github/workflows/build-c-bindings.yml

release_ruby:
name: Release Ruby
runs-on: ubuntu-22.04
needs:
- generate_schemas
- build_rust
steps:
- name: Checkout Repository
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4

- name: Set up Ruby
uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
with:
ruby-version: 3.2

- name: Update version in version.rb
run: |
VERSION_FILE="languages/ruby/infisical-sdk/lib/version.rb"
sed -i.bak "s/VERSION = .*$/VERSION = '${{ github.ref_name }}'/" "$VERSION_FILE"
if [ -f "${VERSION_FILE}.bak" ]; then
rm "${VERSION_FILE}.bak"
fi
- name: Download Ruby schemas artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: sdk-schemas-ruby
path: languages/ruby/infisical-sdk/lib/

# x64 Apple Darwin
- name: Download x86_64-apple-darwin files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-apple-darwin
path: temp/macos-x64

# ARM64 Apple Darwin
- name: Download aarch64-apple-darwin files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-aarch64-apple-darwin
path: temp/macos-arm64

# x64 Linux GNU
- name: Download x86_64-unknown-linux-gnu files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-unknown-linux-gnu
path: temp/linux-x64

# ARM64 Linux GNU
- name: Download aarch64-unknown-linux-gnu files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-aarch64-unknown-linux-gnu
path: temp/linux-arm64

# MSVC x86/x64 Windows
- name: Download x86_64-pc-windows-msvc files
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: libinfisical_c_files-x86_64-pc-windows-msvc
path: temp/windows-x64

- name: Copy lib files
run: |
mkdir -p languages/ruby/infisical-sdk/lib/macos-arm64
mkdir -p languages/ruby/infisical-sdk/lib/linux-x64
mkdir -p languages/ruby/infisical-sdk/lib/linux-arm64
mkdir -p languages/ruby/infisical-sdk/lib/macos-x64
mkdir -p languages/ruby/infisical-sdk/lib/windows-x64
platforms=("macos-arm64" "linux-x64" "linux-arm64" "macos-x64" "windows-x64")
files=("libinfisical_c.dylib" "libinfisical_c.so" "libinfisical_c.so" "libinfisical_c.dylib" "infisical_c.dll")
for ((i=0; i<${#platforms[@]}; i++)); do
cp "temp/${platforms[$i]}/${files[$i]}" "languages/ruby/infisical-sdk/lib/${platforms[$i]}/${files[$i]}"
done
- name: bundle install
run: bundle install
working-directory: languages/ruby/infisical-sdk

- name: Build gem
run: gem build infisical-sdk.gemspec
working-directory: languages/ruby/infisical-sdk

- name: Push gem to Rubygems
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem push *.gem
env:
GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
working-directory: languages/ruby/infisical-sdk
18 changes: 13 additions & 5 deletions .github/workflows/rust-test.yml
Original file line number Diff line number Diff line change
@@ -6,12 +6,20 @@ on:
types: [opened, synchronize]

workflow_call:
secrets:
INFISICAL_UNIVERSAL_CLIENT_SECRET:
required: true
INFISICAL_UNIVERSAL_CLIENT_ID:
required: true
INFISICAL_PROJECT_ID:
required: true
INFISICAL_SITE_URL:
required: true

jobs:
test:
name: Functional tests
runs-on: ubuntu-latest
environment: infisical-test-workspace
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -24,9 +32,9 @@ jobs:
- name: 📦 Cargo test
uses: actions-rs/cargo@v1
env:
INFISICAL_UNIVERSAL_CLIENT_SECRET: "${{ vars.INFISICAL_UNIVERSAL_CLIENT_SECRET }}"
INFISICAL_UNIVERSAL_CLIENT_ID: "${{ vars.INFISICAL_UNIVERSAL_CLIENT_ID }}"
INFISICAL_PROJECT_ID: "${{ vars.INFISICAL_PROJECT_ID }}"
INFISICAL_SITE_URL: "${{ vars.INFISICAL_SITE_URL }}"
INFISICAL_UNIVERSAL_CLIENT_SECRET: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_SECRET }}
INFISICAL_UNIVERSAL_CLIENT_ID: ${{ secrets.INFISICAL_UNIVERSAL_CLIENT_ID }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }}
with:
command: test
14 changes: 13 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -148,10 +148,14 @@ dist
crates/infisical-napi/*.node
languages/node/*.node

languages/node/examples/lambda-node/**/*


# Schemas, no reason having these on github because they're auto generated
crates/infisical-napi/**/schemas.ts
languages/*/**/schemas.*
!languages/*/**/extended_schemas/schemas.rb


.DS_Store

@@ -172,6 +176,8 @@ InfisicalClient.egg-info

__pycache__
crates/infisical-py/infisical_client/schemas.py
crates/infisical-py/infisical_client/infisical_py.*.so
crates/infisical-py/infisical_client/infisical_py.*.dll


infisical_py.so
@@ -192,4 +198,10 @@ languages/csharp/Infisical.Sdk.Samples/bin/**/*

languages/node/npm/**/*.node
languages/node/artifacts
languages/node/package/**/*
languages/node/package/**/*


languages/ruby/infisical-sdk/Gemfile.lock
languages/ruby/infisical-sdk/pkg

languages/java/gradle.properties
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"napi",
"openapi",
"openapitools",
"pyclass",
"pymethods",
"quicktype",
"reqwest",
"rngs"
14 changes: 14 additions & 0 deletions crates/infisical-json/src/client.rs
Original file line number Diff line number Diff line change
@@ -46,6 +46,20 @@ impl Client {
Command::CreateSymmetricKey(_) => {
self.0.cryptography().create_symmetric_key().into_string()
}

// Authentication
Command::UniversalAuthLogin(req) => {
self.0.auth().universal_login(&req).await.into_string()
}
Command::KubernetesAuthLogin(req) => {
self.0.auth().kubernetes_login(&req).await.into_string()
}
Command::AzureAuthLogin(req) => self.0.auth().azure_login(&req).await.into_string(),
Command::GcpIdTokenAuthLogin(req) => {
self.0.auth().gcp_id_token_login(&req).await.into_string()
}
Command::GcpIamAuthLogin(req) => self.0.auth().gcp_iam_login(&req).await.into_string(),
Command::AwsIamAuthLogin(req) => self.0.auth().aws_iam_login(&req).await.into_string(),
}
}

12 changes: 12 additions & 0 deletions crates/infisical-json/src/command.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,11 @@ use infisical::manager::secrets::{

use infisical::manager::cryptography::{DecryptSymmetricOptions, EncryptSymmetricOptions};

use infisical::client::auth_method_settings::{
AWSIamAuthMethod, AzureAuthMethod, GCPIamAuthMethod, GCPIdTokenAuthMethod,
KubernetesAuthMethod, UniversalAuthMethod,
};

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

@@ -28,4 +33,11 @@ pub enum Command {
CreateSymmetricKey(ArbitraryOptions),
EncryptSymmetric(EncryptSymmetricOptions),
DecryptSymmetric(DecryptSymmetricOptions),

UniversalAuthLogin(UniversalAuthMethod),
KubernetesAuthLogin(KubernetesAuthMethod),
AzureAuthLogin(AzureAuthMethod),
GcpIdTokenAuthLogin(GCPIdTokenAuthMethod),
GcpIamAuthLogin(GCPIamAuthMethod),
AwsIamAuthLogin(AWSIamAuthMethod),
}
3 changes: 2 additions & 1 deletion crates/infisical-py/Cargo.toml
Original file line number Diff line number Diff line change
@@ -10,8 +10,9 @@ crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.20.0", features = ["extension-module"] }
pyo3-log = "0.9.0"
infisical-json = { path = "../infisical-json" }
env_logger = "0.9.3"
log = "0.4.20"

[build-dependencies]
pyo3-build-config = { version = "0.20.0" }
13 changes: 12 additions & 1 deletion crates/infisical-py/infisical_client/__init__.py
Original file line number Diff line number Diff line change
@@ -16,4 +16,15 @@
from .schemas import EncryptSymmetricResponse as EncryptSymmetricResponse

from .schemas import DecryptSymmetricOptions as DecryptSymmetricOptions
from .schemas import DecryptSymmetricResponse as DecryptSymmetricResponse
from .schemas import DecryptSymmetricResponse as DecryptSymmetricResponse


# Auth related
from .schemas import AuthenticationOptions as AuthenticationOptions

from .schemas import AWSIamAuthMethod as AWSIamAuthMethod
from .schemas import GCPIamAuthMethod as GCPIamAuthMethod
from .schemas import GCPIDTokenAuthMethod as GCPIDTokenAuthMethod
from .schemas import UniversalAuthMethod as UniversalAuthMethod
from .schemas import AzureAuthMethod as AzureAuthMethod
from .schemas import KubernetesAuthMethod as KubernetesAuthMethod
17 changes: 10 additions & 7 deletions crates/infisical-py/infisical_client/infisical_client.py
Original file line number Diff line number Diff line change
@@ -8,25 +8,25 @@
from .schemas import CreateSecretOptions, ResponseForCreateSecretResponse

from .schemas import EncryptSymmetricOptions, EncryptSymmetricResponse, ResponseForEncryptSymmetricResponse
from .schemas import DecryptSymmetricOptions, DecryptSymmetricResponse, ResponseForDecryptSymmetricResponse
from .schemas import DecryptSymmetricOptions, ResponseForDecryptSymmetricResponse

from .schemas import ArbitraryOptions, ResponseForCreateSymmetricKeyResponse

from .infisical_py import InfisicalClient as RustInfisicalClient
import os

class InfisicalClient:
def __init__(self, settings: ClientSettings = None):
def __init__(self, settings: ClientSettings = None, debug: bool = False):

if settings is None:
self.inner = RustInfisicalClient(None)
self.inner = RustInfisicalClient(settings, debug)
else:

settings.user_agent = "infisical-python-sdk"

settings_json = json.dumps(settings.to_dict())

self.inner = RustInfisicalClient(settings_json)
self.inner = RustInfisicalClient(settings_json, debug)

def _run_command(self, command: Command) -> Any:
response_json = self.inner.run_command(json.dumps(command.to_dict()))
@@ -49,10 +49,13 @@ def listSecrets(self, options: ListSecretsOptions) -> List[SecretElement]:
secrets = ResponseForListSecretsResponse.from_dict(result).data.secrets

# Setting the env in Rust is not enough for Python apparently, so we have to do this as well.
for secret in secrets:
if(options.attach_to_process_env):
os.environ[secret.secret_key] = secret.secret_value
if options.attach_to_process_env:
for secret in secrets:
# we need to check if the env variable is already set, if it is we don't want to overwrite it!
if os.environ.get(secret.secret_key) is None:
os.environ[secret.secret_key] = secret.secret_value

return secrets

def updateSecret(self, options: UpdateSecretOptions) -> SecretElement:
result = self._run_command(Command(update_secret=options))
Binary file not shown.
11 changes: 9 additions & 2 deletions crates/infisical-py/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
extern crate log;
use infisical_json::client::Client as JsonClient;
use pyo3::prelude::*;

@@ -7,8 +8,14 @@ pub struct InfisicalClient(JsonClient);
#[pymethods]
impl InfisicalClient {
#[new]
pub fn new(settings_string: Option<String>) -> Self {
pyo3_log::init();
pub fn new(settings_string: Option<String>, debug: Option<bool>) -> Self {
if debug.unwrap_or(false) == true {
// This will only fail if another logger was already initialized, so we can ignore the result
let _ = env_logger::Builder::from_default_env()
.filter_level(log::LevelFilter::Debug)
.try_init();
}

Self(JsonClient::new(settings_string))
}

12 changes: 9 additions & 3 deletions crates/infisical/Cargo.toml
Original file line number Diff line number Diff line change
@@ -5,6 +5,11 @@ edition = "2021"
rust-version = "1.57"

[dependencies]
aws-config = "1.0.1"
aws-credential-types = "1.0.1"
aws-sigv4 = "1.2.1"
http = "1.0.0"
google-iamcredentials1 = "5.0.4"
schemars = { version = ">=0.8, <0.9", features = ["uuid1", "chrono"] }
aes = ">=0.8.2, <0.9"
argon2 = { version = ">=0.5.0, <0.6", features = [
@@ -27,7 +32,8 @@ num-bigint = ">=0.4, <0.5"
num-traits = ">=0.2.15, <0.3"
pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false }
rand = ">=0.8.5, <0.9"
reqwest = { version = ">=0.11, <0.12", features = ["json"], default-features = false}
reqwest = { version = ">=0.11, <0.12", features = ["json", "rustls-tls-manual-roots"], default-features = false}
rustls-platform-verifier = "0.1.0"
rsa = ">=0.9.2, <0.10"
serde = { version = ">=1.0, <2.0", features = ["derive"] }
serde_json = ">=1.0.96, <2.0"
@@ -39,8 +45,8 @@ subtle = ">=2.5.0, <3.0"
thiserror = ">=1.0.40, <2.0"
url = ">=2.3.1, <3"
uuid = { version = ">=1.3.3, <2.0", features = ["serde"] }
opentelemetry-otlp = {version = "0.14.0", features = ["reqwest-rustls"]}
tokio = "1.35.0"
# opentelemetry-otlp = {version = "0.14.0", features = ["reqwest-rustls"]}
tokio = {version = "1.35.0", features = ["full"]}
env_logger = "0.10.1"
seeded-random = "0.6.0"
serial_test = "2.0.0"
57 changes: 0 additions & 57 deletions crates/infisical/src/api/access_token.rs

This file was deleted.

109 changes: 109 additions & 0 deletions crates/infisical/src/api/auth/aws_iam_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use std::collections::HashMap;
use std::time::{Duration, SystemTime};

use crate::api::auth::{auth_infisical_aws, AccessTokenSuccessResponse, AwsIamRequestData};

use crate::error::{api_error_handler, Error, Result};
use crate::Client;
use aws_config::default_provider::credentials::DefaultCredentialsChain;
use aws_credential_types::provider::ProvideCredentials;
use aws_sigv4::{
http_request::{sign, SignableBody, SignableRequest, SigningSettings},
sign::v4,
};

use crate::helper::get_aws_region;
use log::debug;

pub async fn aws_iam_login(
client: &mut Client,
identity_id: String,
) -> Result<AccessTokenSuccessResponse> {
let aws_region = get_aws_region().await?.into_owned();
let aws_region_str: &'static str = Box::leak(aws_region.into_boxed_str());

let credentials = DefaultCredentialsChain::builder()
.region(aws_region_str) // Convert Cow<str> to &str
.build()
.await
.provide_credentials()
.await
.map_err(|e| Error::AwsCredentialsError {
message: e.to_string(),
})?;

let identity = credentials.into();

let mut signing_settings = SigningSettings::default();
signing_settings.expires_in = Some(Duration::from_secs(900));

let signing_params = v4::SigningParams::builder()
.identity(&identity)
.region(aws_region_str) // Use a reference to the owned String
.name("sts")
.time(SystemTime::now())
.settings(signing_settings)
.build()
.map_err(|e| Error::AwsBuildRequestSignerError {
message: e.to_string(),
})?;

let iam_request_url = format!("https://sts.{}.amazonaws.com/", aws_region_str);
let iam_request_body = "Action=GetCallerIdentity&Version=2011-06-15";

let headers: HashMap<String, String> = [
(
"Host".to_string(),
format!("sts.{}.amazonaws.com", aws_region_str),
),
// These are here so the SignedHeaders are correct
("X-Amz-Date".to_string(), "tmp".to_string()),
("X-Amz-Security-Token".to_string(), "tmp".to_string()),
]
.iter()
.cloned()
.collect();

let signable_request = SignableRequest::new(
"POST",
&iam_request_url,
headers.iter().map(|(k, v)| (k.as_str(), v.as_str())),
SignableBody::Bytes(iam_request_body.as_bytes()),
)
.map_err(|e| Error::AwsSignRequestError {
message: e.to_string(),
})?;

let (signing_instructions, _signature) = sign(signable_request, &signing_params.into())
.unwrap()
.into_parts();

let mut signed_request: http::Request<String> =
http::Request::new(iam_request_body.to_string());
signing_instructions.apply_to_request_http1x(&mut signed_request);

let iam_data = AwsIamRequestData {
http_request_method: "POST".to_string(),
iam_request_body: iam_request_body.to_string(),
iam_request_headers: signed_request
.headers()
.iter()
.map(|(k, v)| (k.to_string(), v.to_str().unwrap().to_string()))
.collect(),
};

let response = auth_infisical_aws(client, Some(identity_id), iam_data).await?;
let status = response.status();

debug!("aws_iam_login status: {}", status);

let status = response.status();

if status.is_success() {
let json_response = response.json::<AccessTokenSuccessResponse>().await?;
return Ok(json_response);
} else {
let err = api_error_handler(status, response, None, true).await?;
return Err(err);
}
}
47 changes: 47 additions & 0 deletions crates/infisical/src/api/auth/azure_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use serde::{Deserialize, Serialize};

use crate::{
constants::AZURE_METADATA_SERVICE_URL,
error::{api_error_handler, Result},
helper::build_minimal_base_request,
Client,
};

use super::{auth_infisical_azure, AccessTokenSuccessResponse};

#[derive(Serialize, Deserialize, Debug)]
struct AzureSuccessResponse {
access_token: String,
}

pub async fn azure_login(
client: &mut Client,
identity_id: String,
) -> Result<AccessTokenSuccessResponse> {
let request_client = build_minimal_base_request()?;

let metadata_request = request_client
.get(AZURE_METADATA_SERVICE_URL)
.header("Metadata", "true")
.header(reqwest::header::ACCEPT, "application/json");

let azure_response = metadata_request.send().await?;

if !azure_response.status().is_success() {
let err = api_error_handler(azure_response.status(), azure_response, None, false).await?;
return Err(err);
}

let azure_metadata = azure_response.json::<AzureSuccessResponse>().await?;

let response =
auth_infisical_azure(client, Some(identity_id), Some(azure_metadata.access_token)).await?;

if !response.status().is_success() {
let err = api_error_handler(response.status(), response, None, false).await?;
return Err(err);
}

let response_json = response.json::<AccessTokenSuccessResponse>().await?;
return Ok(response_json);
}
123 changes: 123 additions & 0 deletions crates/infisical/src/api/auth/gcp_iam_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use google_iamcredentials1::oauth2::{read_service_account_key, ServiceAccountAuthenticator};
use google_iamcredentials1::{hyper, hyper_rustls, IAMCredentials};
use serde::{Deserialize, Serialize};

use crate::api::auth::auth_infisical_google;
use crate::{
error::{api_error_handler, Error, Result},
Client,
};
use log::debug;

#[derive(Serialize, Deserialize)]
struct JwtPayload {
sub: String,
aud: String,
}

use super::AccessTokenSuccessResponse;

pub async fn gcp_iam_login(
client: &mut Client,
identity_id: String,
service_account_key_path: String,
) -> Result<AccessTokenSuccessResponse> {
let service_account_key = &read_service_account_key(service_account_key_path).await?;

// Create an authenticator
let auth = ServiceAccountAuthenticator::builder(service_account_key.clone())
.build()
.await?;

// We do this to make sure the token is valid
let token = auth
.token(&["https://www.googleapis.com/auth/cloud-platform"])
.await;

if let Err(e) = token {
return Err(Error::GoogleTokenError {
message: e.to_string(),
});
}

// Get the client email from the credentials
let client_email = service_account_key.client_email.clone();

// Create the JWT payload
let jwt_payload = JwtPayload {
sub: client_email.clone(),
aud: identity_id.to_string(),
};

// Convert the payload to a JSON string
let payload = serde_json::to_string(&jwt_payload)?;

debug!("Payload: {}", payload);

// Create the IAM credentials hub
let https_connector = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()?
.https_or_http()
.enable_http1()
.enable_http2()
.build();

let hyper_client = hyper::Client::builder().build(https_connector);
// let boxed_auth = Box::new(auth) as Box<dyn GetToken>;

// Create the IAM credentials hub
let iam_credentials_hub = IAMCredentials::new(hyper_client, auth);

// Call the IAM service to sign the JWT
let request = google_iamcredentials1::api::SignJwtRequest {
payload: Some(payload),
delegates: None,
};

let response = iam_credentials_hub
.projects()
.service_accounts_sign_jwt(
request,
&format!("projects/-/serviceAccounts/{}", client_email),
)
.doit()
.await;

if let Err(e) = response {
return Err(Error::GoogleJwtError {
message: format!(
"Are you sure you have enabled the IAM Service Account Credentials API?\n{}",
e.to_string()
),
});
}

let signed_jwt = &response.unwrap().1.signed_jwt;

debug!("Signed JWT {:?}", signed_jwt.clone());

// authenticate with infisical!

let response = auth_infisical_google(client, Some(identity_id), signed_jwt.clone()).await;

if let Err(e) = response {
return Err(Error::UnknownErrorWithMessage {
message: e.to_string(),
});
}

let response = response.unwrap();
let status = response.status();

debug!("gcp_id_token_auth_status status: {}", status);

let status = response.status();

if status.is_success() {
let json_response = response.json::<AccessTokenSuccessResponse>().await?;
return Ok(json_response);
} else {
let err = api_error_handler(status, response, None, true).await?;
return Err(err);
}
}
50 changes: 50 additions & 0 deletions crates/infisical/src/api/auth/gcp_id_token_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::{
api::auth::auth_infisical_google,
error::{api_error_handler, Error, Result},
helper::build_minimal_base_request,
Client,
};

use super::AccessTokenSuccessResponse;

pub async fn gcp_id_token_login(
client: &mut Client,
identity_id: String,
) -> Result<AccessTokenSuccessResponse> {
let request_client = build_minimal_base_request()?;

let metadata_request = request_client
.get(format!(
"http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience={}&format=full",
identity_id
))
.header("Metadata-Flavor", "Google");

let metadata_response = metadata_request.send().await?;

let status = metadata_response.status();

if !status.is_success() {
return Err(Error::GoogleMetadataError);
}

let id_token = metadata_response.text().await?;
let response = auth_infisical_google(client, Some(identity_id), Some(id_token)).await;

if let Err(e) = response {
return Err(Error::UnknownErrorWithMessage {
message: e.to_string(),
});
}

let response = response.unwrap();
let status = response.status();

if status.is_success() {
let response = response.json::<AccessTokenSuccessResponse>().await?;
Ok(response)
} else {
let err = api_error_handler(status, response, None, true).await?;
Err(err)
}
}
42 changes: 42 additions & 0 deletions crates/infisical/src/api/auth/kubernetes_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use log::debug;

use crate::{
error::{api_error_handler, Error, Result},
Client,
};

use super::{auth_infisical_kubernetes, AccessTokenSuccessResponse};

pub async fn kubernetes_login(
client: &mut Client,
identity_id: String,
service_account_token_path: String,
) -> Result<AccessTokenSuccessResponse> {
debug!(
"Reading service account token from path: {}",
service_account_token_path
);

let account_token = String::from_utf8(tokio::fs::read(service_account_token_path).await?)
.map_err(|e| Error::UnknownErrorWithMessage {
message: e.to_string(),
})?;

debug!(
"First 10 characters of the K8's account token: {:?}",
&account_token[0..10]
);

let response =
auth_infisical_kubernetes(client, Some(identity_id), Some(account_token)).await?;

let status = response.status();

if status.is_success() {
let response = response.json::<AccessTokenSuccessResponse>().await?;
Ok(response)
} else {
let err = api_error_handler(status, response, None, true).await?;
Err(err)
}
}
126 changes: 126 additions & 0 deletions crates/infisical/src/api/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use std::collections::HashMap;

use base64::Engine;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::{
error::{Error, Result},
helper::build_base_request,
Client,
};

pub mod aws_iam_login;
pub mod azure_login;
pub mod gcp_iam_login;
pub mod gcp_id_token_login;
pub mod kubernetes_login;
pub mod universal_auth_login;

fn base64_encode(plain: String) -> String {
return base64::engine::general_purpose::STANDARD.encode(plain);
}

#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
#[serde(rename_all = "camelCase")]

pub struct AccessTokenSuccessResponse {
pub access_token: String,
pub expires_in: i64,
#[serde(rename = "accessTokenMaxTTL")]
pub access_token_max_ttl: i64,
pub token_type: String,
}

#[derive(Serialize)]
pub(self) struct AwsIamRequestData {
http_request_method: String,
// base64 encoded body
iam_request_body: String,
// json stringified headers
iam_request_headers: HashMap<String, String>,
}

// Universal method for getting infisical token through google auth methods
pub(self) async fn auth_infisical_google(
client: &mut Client,
identity_id: Option<String>,
jwt: Option<String>,
) -> Result<reqwest::Response> {
let url = format!("{}/api/v1/auth/gcp-auth/login", client.site_url.clone());
let request = build_base_request(client, &url, reqwest::Method::POST).await?;

let mut body = HashMap::new();
body.insert("identityId", identity_id);
body.insert("jwt", jwt);

let response = request.form(&body).send().await?;

return Ok(response);
}

pub(self) async fn auth_infisical_azure(
client: &mut Client,
identity_id: Option<String>,
jwt: Option<String>,
) -> Result<reqwest::Response> {
let url = format!("{}/api/v1/auth/azure-auth/login", client.site_url.clone());
let request = build_base_request(client, &url, reqwest::Method::POST).await?;

let mut body = HashMap::new();
body.insert("identityId", identity_id);
body.insert("jwt", jwt);

let response = request.form(&body).send().await?;

return Ok(response);
}

pub(self) async fn auth_infisical_kubernetes(
client: &mut Client,
identity_id: Option<String>,
jwt: Option<String>,
) -> Result<reqwest::Response> {
let url = format!(
"{}/api/v1/auth/kubernetes-auth/login",
client.site_url.clone()
);
let request = build_base_request(client, &url, reqwest::Method::POST).await?;

let mut body = HashMap::new();
body.insert("identityId", identity_id);
body.insert("jwt", jwt);

let response = request.form(&body).send().await?;

return Ok(response);
}

pub(self) async fn auth_infisical_aws(
client: &mut Client,
identity_id: Option<String>,
iam_data: AwsIamRequestData,
) -> Result<reqwest::Response> {
let header_json = serde_json::to_string(&iam_data.iam_request_headers).map_err(|e| {
Error::UnknownErrorWithMessage {
message: e.to_string(),
}
})?;

let iam_headers = base64_encode(header_json);
let request_body = base64_encode(iam_data.iam_request_body.clone());

let url = format!("{}/api/v1/auth/aws-auth/login", client.site_url.clone());
let request = build_base_request(client, &url, reqwest::Method::POST).await?;

let mut form_data = HashMap::new();

form_data.insert("identityId", identity_id);
form_data.insert("iamHttpRequestMethod", Some(iam_data.http_request_method));
form_data.insert("iamRequestBody", Some(request_body));
form_data.insert("iamRequestHeaders", Some(iam_headers));

let response = request.form(&form_data).send().await?;

return Ok(response);
}
42 changes: 42 additions & 0 deletions crates/infisical/src/api/auth/universal_auth_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::{
error::{api_error_handler, Result},
helper::build_base_request,
Client,
};
use log::debug;

use std::collections::HashMap;

use super::AccessTokenSuccessResponse;

pub async fn universal_auth_login(
client: &mut Client,
client_id: String,
client_secret: String,
) -> Result<AccessTokenSuccessResponse> {
let mut body = HashMap::new();
body.insert("clientId", Some(client_id));
body.insert("clientSecret", Some(client_secret));
let request_body = serde_json::to_string(&body).unwrap();

let url = format!(
"{}/api/v1/auth/universal-auth/login",
client.site_url.clone()
);

let request = build_base_request(client, &url, reqwest::Method::POST).await?;

let response = request.body(request_body).send().await?;

debug!("universal_auth_login status: {}", response.status());

let status = response.status();

if status.is_success() {
let response = response.json::<AccessTokenSuccessResponse>().await?;
Ok(response)
} else {
let err = api_error_handler(status, response, None, true).await?;
Err(err)
}
}
2 changes: 1 addition & 1 deletion crates/infisical/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod access_token;
pub mod auth;
pub mod secrets;

use schemars::JsonSchema;
10 changes: 3 additions & 7 deletions crates/infisical/src/api/secrets/create_secret.rs
Original file line number Diff line number Diff line change
@@ -29,12 +29,7 @@ pub async fn create_secret_request(

});

let base_request = build_base_request(client, &base_url, reqwest::Method::POST);

let request = match base_request {
Ok(request) => request,
Err(e) => return Err(e),
};
let base_request = build_base_request(client, &base_url, reqwest::Method::POST).await?;

let token = match client.auth.access_token {
Some(ref token) => format!("Bearer {}", token),
@@ -46,7 +41,7 @@ pub async fn create_secret_request(
debug!("Creating secret with JSON body: {:?}", json);
debug!("Creating secret with url: {}", base_url);

let response = request.json(json).send().await?;
let response = base_request.json(json).send().await?;
let status = response.status();

if status == StatusCode::OK {
@@ -58,6 +53,7 @@ pub async fn create_secret_request(
&response.secret.secret_key,
&response.secret.r#type,
&response.secret.environment,
input.path.as_ref().unwrap_or(&"/".to_string()),
);

Ok(response)
10 changes: 3 additions & 7 deletions crates/infisical/src/api/secrets/delete_secret.rs
Original file line number Diff line number Diff line change
@@ -23,12 +23,7 @@ pub async fn delete_secret_request(
"secretPath": input.path.as_ref().unwrap_or(&"/".to_string()),
});

let base_request = build_base_request(client, &base_url, reqwest::Method::DELETE);

let request = match base_request {
Ok(request) => request,
Err(e) => return Err(e),
};
let base_request = build_base_request(client, &base_url, reqwest::Method::DELETE).await?;

let token = match client.auth.access_token {
Some(ref token) => format!("Bearer {}", token),
@@ -39,7 +34,7 @@ pub async fn delete_secret_request(
debug!("Creating secret with JSON body: {:?}", json);
debug!("Creating secret with url: {}", base_url);

let response = request.json(json).send().await?;
let response = base_request.json(json).send().await?;
let status = response.status();

if status == StatusCode::OK {
@@ -51,6 +46,7 @@ pub async fn delete_secret_request(
&response.secret.secret_key,
&response.secret.r#type,
&response.secret.environment,
input.path.as_ref().unwrap_or(&"/".to_string()),
);

Ok(response)
35 changes: 23 additions & 12 deletions crates/infisical/src/api/secrets/get_secret.rs
Original file line number Diff line number Diff line change
@@ -19,18 +19,30 @@ pub async fn get_secret_request(
let json: &serde_json::Value = &serde_json::json!({
"workspaceId": input.project_id,
"environment": input.environment,
"secretPath": input.path.as_ref().unwrap_or(&"/".to_string()), // default is "/"
"type": input.r#type.as_ref().unwrap_or(&"shared".to_string()), // default is shared
"include_imports": input.include_imports.as_ref().unwrap_or(&false), // default is false
"secretPath": input.path.clone().unwrap_or("/".to_string()), // default is "/"
"expandSecretReferences": input.expand_secret_references.unwrap_or(true).to_string(),
"type": input.r#type.clone().unwrap_or("shared".to_string()), // default is shared
"include_imports": input.include_imports.unwrap_or(false).to_string(),
});

let secret_type = match input.r#type.as_ref() {
Some(r#type) => r#type,
None => "shared",
};

let secret_path = match input.path.as_ref() {
Some(path) => path,
None => "/",
};

let cached_secret = get_secret_from_cache(
client,
&create_cache_key(&input.secret_name, secret_type, &input.environment),
&create_cache_key(
&input.secret_name,
secret_type,
&input.environment,
secret_path,
),
);

if cached_secret.is_some() {
@@ -41,7 +53,7 @@ pub async fn get_secret_request(

let url = build_url(base_url, json);

let base_request = build_base_request(client, &url, reqwest::Method::GET);
let base_request = build_base_request(client, &url, reqwest::Method::GET).await?;

let token = match client.auth.access_token {
Some(ref token) => format!("Bearer {}", token),
@@ -53,19 +65,18 @@ pub async fn get_secret_request(
debug!("Getting secret with body: {:?}", input);
debug!("Getting secret with url: {}", url);

let request = match base_request {
Ok(request) => request,
Err(e) => return Err(e),
};

let response = request.send().await?;
let response = base_request.send().await?;

let status = response.status();

if status == StatusCode::OK {
let response = response.json::<GetSecretResponse>().await?;

add_to_cache(client, &response.secret);
add_to_cache(
client,
&response.secret,
input.path.as_ref().unwrap_or(&"/".to_string()),
);

Ok(response)
} else {
59 changes: 34 additions & 25 deletions crates/infisical/src/api/secrets/list_secrets.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::api_error_handler;
use crate::helper::{build_base_request, build_url};
use crate::helper::{build_base_request, build_url, ensure_unique_secrets_by_key, set_env_vars};
use crate::manager::secrets::{ListSecretsOptions, ListSecretsResponse, Secret};
use crate::{error::Result, Client};
use log::debug;
@@ -31,61 +31,70 @@ pub async fn list_secrets_request(
"environment": input.environment,
"workspaceId": input.project_id,

"expandSecretReferences": input.expand_secret_references.unwrap_or(true).to_string(),
"recursive": input.recursive.unwrap_or(false).to_string(),
"secretPath": input.path.as_ref().unwrap_or(&"/".to_string()), // default is "/"
"include_imports": input.include_imports.unwrap_or(false).to_string(),

});

let url = build_url(base_url, json);

let base_request = build_base_request(client, &url, reqwest::Method::GET);

let request = match base_request {
Ok(request) => request,
Err(e) => return Err(e),
};
let url = &build_url(base_url, json);
let base_request = build_base_request(client, url, reqwest::Method::GET).await?;

let token = match client.auth.access_token {
Some(ref token) => format!("Bearer {}", token),
None => "".to_string(),
};

debug!("Creating secret with token: {}", token);

debug!("Creating secret with JSON body: {:?}", json);
debug!("Creating secret with url: {}", url);

let response = request.json(json).send().await?;
let response = base_request.json(json).send().await?;
let status = response.status();

if status == StatusCode::OK {
if input.include_imports.unwrap_or(false) == true {
let response = response.json::<ImportResponse>().await?;
let mut response = response.json::<ImportResponse>().await?;

if input.recursive.unwrap_or(false) == true {
ensure_unique_secrets_by_key(&mut response.secrets);
}

let mut secrets = response.secrets.clone();

for import in response.imports {
secrets.extend(import.secrets);
}

if input.attach_to_process_env.unwrap_or(false) == true {
for secret in secrets.clone() {
std::env::set_var(secret.secret_key, secret.secret_value);
for import_secret in import.secrets.clone() {
// CASE: We need to ensure that the imported values don't override the "base" secrets.
// Priority order is:
// Local/Preset variables -> Actual secrets -> Imported secrets (high->low)

// Check if the secret already exists in the secrets list
if !secrets
.iter()
.any(|secret| secret.secret_key == import_secret.secret_key)
{
secrets.push(import_secret);
}
}
}

set_env_vars(input.attach_to_process_env.unwrap_or(false), &secrets);

return Ok(ListSecretsResponse { secrets });
}
let mut response = response.json::<ListSecretsResponse>().await?;

let response = response.json::<ListSecretsResponse>().await?;
if input.recursive.unwrap_or(false) == true {
ensure_unique_secrets_by_key(&mut response.secrets);
}

if input.attach_to_process_env.unwrap_or(false) == true {
let secrets = response.secrets.clone();
set_env_vars(
input.attach_to_process_env.unwrap_or(false),
&response.secrets,
);

for secret in secrets {
std::env::set_var(secret.secret_key, secret.secret_value);
}
}
debug!("Secrets: {:?}", response);

Ok(response)
} else {
10 changes: 3 additions & 7 deletions crates/infisical/src/api/secrets/update_secret.rs
Original file line number Diff line number Diff line change
@@ -26,14 +26,9 @@ pub async fn update_secret_request(

});

let base_request = build_base_request(client, &base_url, reqwest::Method::PATCH);
let base_request = build_base_request(client, &base_url, reqwest::Method::PATCH).await?;

let request = match base_request {
Ok(request) => request,
Err(e) => return Err(e),
};

let response = request.json(json).send().await?;
let response = base_request.json(json).send().await?;
let status = response.status();

if status == StatusCode::OK {
@@ -45,6 +40,7 @@ pub async fn update_secret_request(
&response.secret.secret_key,
&response.secret.r#type,
&response.secret.environment,
input.path.as_ref().unwrap_or(&"/".to_string()),
);

Ok(response)
25 changes: 0 additions & 25 deletions crates/infisical/src/auth/authenticate.rs

This file was deleted.

5 changes: 1 addition & 4 deletions crates/infisical/src/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
pub mod authenticate;

pub use crate::api::access_token::AccessTokenSuccessResponse;
pub use authenticate::UpdateAccessTokenRequest;
pub use crate::api::auth::AccessTokenSuccessResponse;
24 changes: 19 additions & 5 deletions crates/infisical/src/cache.rs
Original file line number Diff line number Diff line change
@@ -24,17 +24,30 @@ fn get_sys_time_in_ms() -> Result<u64, SystemTimeError> {
return Ok(sec * 1000);
}

pub fn create_cache_key(secret_key: &str, secret_type: &str, environment: &str) -> String {
return format!("{}-{}-{}", secret_key, environment, secret_type);
pub fn create_cache_key(
secret_key: &str,
secret_type: &str,
environment: &str,
secret_path: &str,
) -> String {
return format!(
"{}-{}-{}-{}",
secret_key, environment, secret_type, secret_path
);
}

pub fn add_to_cache(client: &mut Client, secret: &Secret) {
pub fn add_to_cache(client: &mut Client, secret: &Secret, secret_path: &str) {
if client.cache_ttl == 0 {
debug!("[CACHE]: Cache TTL is set to 0, not adding secret to cache.");
return;
}

let key = create_cache_key(&secret.secret_key, &secret.r#type, &secret.environment);
let key = create_cache_key(
&secret.secret_key,
&secret.r#type,
&secret.environment,
secret_path,
);

let existing_secret = get_secret_from_cache(client, &key);

@@ -72,13 +85,14 @@ pub fn remove_from_cache(
secret_key: &str,
secret_type: &str,
environment: &str,
secret_path: &str,
) {
if client.cache_ttl == 0 {
debug!("[CACHE]: Cache TTL is set to 0, not removing secret from cache.");
return;
}

let key = create_cache_key(&secret_key, &secret_type, &environment);
let key = create_cache_key(secret_key, secret_type, environment, secret_path);

let mut cache = client.cache.lock().unwrap();

269 changes: 269 additions & 0 deletions crates/infisical/src/client/auth_method_settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
use log::debug;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::constants::{
INFISICAL_ACCESS_TOKEN_ENV_NAME, INFISICAL_AWS_IAM_AUTH_IDENTITY_ID_ENV_NAME,
INFISICAL_AZURE_AUTH_IDENTITY_ID_ENV_NAME, INFISICAL_GCP_AUTH_IDENTITY_ID_ENV_NAME,
INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH_ENV_NAME,
INFISICAL_KUBERNETES_IDENTITY_ID_ENV_NAME,
INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH_ENV_NAME,
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_ENV_NAME, INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_ENV_NAME,
};

fn default_kubernetes_service_account_token_path() -> Option<String> {
Some("/var/run/secrets/kubernetes.io/serviceaccount/token".to_string())
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct UniversalAuthMethod {
pub client_id: String,
pub client_secret: String,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct GCPIdTokenAuthMethod {
pub identity_id: String,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct GCPIamAuthMethod {
#[schemars(
description = "The path to the GCP Service Account key file.\n\n You can generate this key file by going to the GCP Console -> IAM & Admin -> Service Accounts -> *Select your service account* -> Keys tab -> Add key.\nNote: The key must be in JSON format."
)]
pub service_account_key_file_path: String,
pub identity_id: String,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct AWSIamAuthMethod {
#[schemars(
description = "The Infisical Identity ID that you want to authenticate to Infisical with."
)]
pub identity_id: String,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct KubernetesAuthMethod {
#[schemars(
description = "The Infisical Identity ID that you want to authenticate to Infisical with."
)]
pub identity_id: String,

#[schemars(
description = "The path to the Kubernetes Service Account token file.\n\nIf no path is provided, it will default to /var/run/secrets/kubernetes.io/serviceaccount/token."
)]
#[serde(default = "default_kubernetes_service_account_token_path")]
pub service_account_token_path: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct AzureAuthMethod {
#[schemars(
description = "The Infisical Identity ID that you want to authenticate to Infisical with."
)]
pub identity_id: String,
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(default, rename_all = "camelCase")]
pub struct AuthenticationOptions {
pub access_token: Option<String>,
pub universal_auth: Option<UniversalAuthMethod>,
pub kubernetes: Option<KubernetesAuthMethod>,
pub azure: Option<AzureAuthMethod>,
pub gcp_id_token: Option<GCPIdTokenAuthMethod>,
pub gcp_iam: Option<GCPIamAuthMethod>,
pub aws_iam: Option<AWSIamAuthMethod>,
}

impl Default for AuthenticationOptions {
fn default() -> Self {
Self {
access_token: None,
universal_auth: None,
gcp_id_token: None,
gcp_iam: None,
aws_iam: None,
kubernetes: None,
azure: None,
}
}
}

#[derive(Debug)]
pub enum AuthMethod {
UniversalAuth,
Kubernetes,
Azure,
GcpIdToken,
GcpIam,
AwsIam,
AccessToken,
}

// Custom validation to ensure that if universal_auth or gcp_auth are present, their fields are populated
impl AuthenticationOptions {
pub fn validate(&mut self) -> Result<AuthMethod, String> {
// ACCESS TOKEN:
if let Some(ref access_token) = self.access_token {
if !access_token.is_empty() {
return Ok(AuthMethod::AccessToken);
}
return Err("access_token is present but is empty".into());
}

// UNIVERSAL AUTH:
if let Some(ref auth) = self.universal_auth {
if !auth.client_id.is_empty() && !auth.client_secret.is_empty() {
return Ok(AuthMethod::UniversalAuth);
}

return Err("universal_auth is present but client_id or client_secret is empty".into());
}
// GCP ID TOKEN AUTH:
else if let Some(ref auth) = self.gcp_id_token {
if !auth.identity_id.is_empty() {
return Ok(AuthMethod::GcpIdToken);
}
return Err("gcp_auth is present but identity_id is empty".into());
}
// GCP IAM AUTH:
else if let Some(ref auth) = self.gcp_iam {
if !auth.service_account_key_file_path.is_empty() && !auth.identity_id.is_empty() {
return Ok(AuthMethod::GcpIam);
}
return Err("gcp_auth is present but service_account_key_file_path is empty".into());
}
// AWS IAM AUTH:
else if let Some(ref auth) = self.aws_iam {
if !auth.identity_id.is_empty() {
return Ok(AuthMethod::AwsIam);
}
return Err("aws_iam is present but identity_id is empty".into());
}
// KUBERNETES AUTH:
else if let Some(ref auth) = self.kubernetes {
if !auth.identity_id.is_empty() {
return Ok(AuthMethod::Kubernetes);
}
return Err("kubernetes auth is present but identity_id is empty".into());

// AZURE AUTH:
} else if let Some(ref auth) = self.azure {
if !auth.identity_id.is_empty() {
return Ok(AuthMethod::Azure);
}
return Err("azure auth is present but identity_id is empty".into());
} else {
debug!("No authentication method is set. Checking environment variables.");

// access token env
let access_token_env =
std::env::var(INFISICAL_ACCESS_TOKEN_ENV_NAME).unwrap_or_default();

// universal auth env's
let universal_auth_client_id_env =
std::env::var(INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_ENV_NAME).unwrap_or_default();
let universal_auth_client_secret_env =
std::env::var(INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_ENV_NAME).unwrap_or_default();

// gcp auth env's
let gcp_auth_identity_id_env =
std::env::var(INFISICAL_GCP_AUTH_IDENTITY_ID_ENV_NAME).unwrap_or_default();
let gcp_iam_service_account_key_file_path_env =
std::env::var(INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH_ENV_NAME)
.unwrap_or_default();

// aws iam auth env's
let aws_iam_identity_id_env =
std::env::var(INFISICAL_AWS_IAM_AUTH_IDENTITY_ID_ENV_NAME).unwrap_or_default();

// kubernetes auth env's
let kubernetes_identity_id_env =
std::env::var(INFISICAL_KUBERNETES_IDENTITY_ID_ENV_NAME).unwrap_or_default();
let kubernetes_service_account_token_path_env =
std::env::var(INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH_ENV_NAME)
.unwrap_or_default();

// azure auth env's
let azure_auth_identity_id_env =
std::env::var(INFISICAL_AZURE_AUTH_IDENTITY_ID_ENV_NAME).unwrap_or_default();

// access token env check
if !access_token_env.is_empty() {
self.access_token = Some(access_token_env);
return Ok(AuthMethod::AccessToken);
}

// universal auth env check
if !universal_auth_client_id_env.is_empty()
&& !universal_auth_client_secret_env.is_empty()
{
self.universal_auth = Some(UniversalAuthMethod {
client_id: universal_auth_client_id_env,
client_secret: universal_auth_client_secret_env,
});

return Ok(AuthMethod::UniversalAuth);
}

// aws iam auth env check
if !aws_iam_identity_id_env.is_empty() {
self.aws_iam = Some(AWSIamAuthMethod {
identity_id: aws_iam_identity_id_env,
});

return Ok(AuthMethod::AwsIam);
}

// gcp iam auth env check
if !gcp_iam_service_account_key_file_path_env.is_empty()
&& !gcp_auth_identity_id_env.is_empty()
{
self.gcp_iam = Some(GCPIamAuthMethod {
service_account_key_file_path: gcp_iam_service_account_key_file_path_env,
identity_id: gcp_auth_identity_id_env,
});
return Ok(AuthMethod::GcpIam);
}

// gcp id token auth env check
if !gcp_auth_identity_id_env.is_empty() {
self.gcp_id_token = Some(GCPIdTokenAuthMethod {
identity_id: gcp_auth_identity_id_env,
});

return Ok(AuthMethod::GcpIdToken);
}

// kubernetes auth env check
if !kubernetes_identity_id_env.is_empty() {
self.kubernetes = Some(KubernetesAuthMethod {
identity_id: kubernetes_identity_id_env,
service_account_token_path: Some(kubernetes_service_account_token_path_env)
.or(default_kubernetes_service_account_token_path()),
});

return Ok(AuthMethod::Kubernetes);
}

// azure auth env check
if !azure_auth_identity_id_env.is_empty() {
self.azure = Some(AzureAuthMethod {
identity_id: azure_auth_identity_id_env,
});

return Ok(AuthMethod::Azure);
}

return Err("No authentication method is set.".into());
}
}
}
47 changes: 29 additions & 18 deletions crates/infisical/src/client/client.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
use crate::{
cache::{cache_thread, CachedSecret},
client::client_settings::ClientSettings,
client::{auth_method_settings::UniversalAuthMethod, client_settings::ClientSettings},
};
use std::sync::{Arc, Mutex};
pub(crate) struct ClientAuth {
pub client_id: String,
pub client_secret: String,
pub access_token: Option<String>,
}

use super::auth_method_settings::AuthenticationOptions;
pub struct Client {
pub(crate) auth: ClientAuth,
pub(crate) auth: AuthenticationOptions,

pub(crate) cache: Arc<Mutex<Vec<CachedSecret>>>,
pub(crate) cache_ttl: u64, // No need for a mutex lock here, as we are only reading this value in the cache thread.
pub(crate) ssl_certificate_path: Option<String>,

pub site_url: String,
pub user_agent: String,
}

impl Client {
pub fn new(settings_input: Option<ClientSettings>) -> Self {
let settings = settings_input.expect("Settings not found or were set improperly.");

let c = Self {
auth: ClientAuth {
client_id: settings.client_id.unwrap_or("".to_string()),
client_secret: settings.client_secret.unwrap_or("".to_string()),
access_token: settings.access_token,
},
// We should allow the user to not provide settings, so they can still use encryption methods that don't require authentication.
let mut settings = settings_input.unwrap_or(ClientSettings::default());

// Move the deprecated fields to the new auth object for backwards compatibility.
#[allow(deprecated)]
{
if settings.auth.access_token.is_none() {
settings.auth.access_token = settings.access_token;
}

if settings.client_id.is_some() && settings.client_secret.is_some() {
settings.auth.universal_auth = Some(UniversalAuthMethod {
client_id: settings.client_id.unwrap(),
client_secret: settings.client_secret.unwrap(),
});
}
}

let client: Client = Self {
auth: settings.auth,
ssl_certificate_path: settings.ssl_certificate_path,
site_url: settings
.site_url
.unwrap_or("https://app.infisical.com".to_string()),
@@ -37,10 +48,10 @@ impl Client {
user_agent: settings.user_agent.unwrap_or("".to_string()),
};

if c.cache_ttl != 0 {
cache_thread(Arc::clone(&c.cache));
if client.cache_ttl != 0 {
cache_thread(Arc::clone(&client.cache));
}
return c;
return client;
}

pub fn set_access_token(&mut self, token: String) {
39 changes: 37 additions & 2 deletions crates/infisical/src/client/client_settings.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,64 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::auth_method_settings::AuthenticationOptions;

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(default, rename_all = "camelCase")]
pub struct ClientSettings {
// These are optional because the access token can be set directly as well
#[deprecated]
#[schemars(
description = "**DEPRECATED**: The client secret field is deprecated. Please use the new auth object field instead."
)]
pub client_secret: Option<String>,

#[deprecated]
#[schemars(
description = "**DEPRECATED**: The client secret field is deprecated. Please use the new auth object field instead."
)]
pub client_id: Option<String>,

#[deprecated]
#[schemars(
description = "**DEPRECATED**: The access token field is deprecated. Please use the new auth object field instead."
)]
pub access_token: Option<String>,

// Access token is optional because the user can also provide a machine token.
#[schemars(
description = "The URL of the site to connect to. Defaults to \"https://app.infisical.com\"."
)]
pub site_url: Option<String>,

pub cache_ttl: Option<u64>, // This controls how often the cache should refresh, default is 300 seconds
#[schemars(
description = "cacheTTL controls how often the cache should refresh, default is 300 seconds. Set to 0 to disable the cache."
)]
pub cache_ttl: Option<u64>,
pub user_agent: Option<String>, // We use this to identity which SDK/language was used to make a request.

#[schemars(
description = "The SSL certificate path is an optional field that allows you to specify a custom SSL certificate to use for requests made to Infisical.
This option can be substituted with the `INFISICAL_SSL_CERTIFICATE` environment variable, which should contain the certificate as a string, not the path."
)]
pub ssl_certificate_path: Option<String>, // Path to the SSL certificate file.

#[schemars(
description = "Configure the authentication method to use.\n\nMake sure to only set one one method at a time to avoid conflicts and unexpected behavior."
)]
pub auth: AuthenticationOptions,
}

#[allow(deprecated)]
impl Default for ClientSettings {
fn default() -> Self {
Self {
ssl_certificate_path: None,
client_secret: None,
client_id: None,
access_token: None,
site_url: None,
cache_ttl: None,
auth: AuthenticationOptions::default(),
user_agent: Some("infisical-unknown-sdk".to_string()),
}
}
1 change: 1 addition & 0 deletions crates/infisical/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod auth_method_settings;
mod client;
pub mod client_settings;
pub use client::Client;
35 changes: 35 additions & 0 deletions crates/infisical/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Universal auth:
pub const INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_ENV_NAME: &str = "INFISICAL_UNIVERSAL_AUTH_CLIENT_ID";
pub const INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_ENV_NAME: &str =
"INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET";

// GCP Auth:
pub const INFISICAL_GCP_AUTH_IDENTITY_ID_ENV_NAME: &str = "INFISICAL_GCP_AUTH_IDENTITY_ID";
pub const INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH_ENV_NAME: &str =
"INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH";

// AWS IAM Auth:
pub const INFISICAL_AWS_IAM_AUTH_IDENTITY_ID_ENV_NAME: &str = "INFISICAL_AWS_IAM_AUTH_IDENTITY_ID";

// Kubernetes Auth:
pub const INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH_ENV_NAME: &str =
// /var/run/secrets/kubernetes.io/serviceaccount/token
"INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH";

// Azure Auth:
pub const INFISICAL_AZURE_AUTH_IDENTITY_ID_ENV_NAME: &str = "INFISICAL_AZURE_AUTH_IDENTITY_ID";

pub const INFISICAL_KUBERNETES_IDENTITY_ID_ENV_NAME: &str = "INFISICAL_KUBERNETES_IDENTITY_ID";

pub const INFISICAL_ACCESS_TOKEN_ENV_NAME: &str = "INFISICAL_ACCESS_TOKEN";

// AWS EC2 Metadata Service:
pub const AWS_EC2_METADATA_TOKEN_URL: &str = "http://169.254.169.254/latest/api/token";
pub const AWS_EC2_INSTANCE_IDENTITY_DOCUMENT_URL: &str =
"http://169.254.169.254/latest/dynamic/instance-identity/document";

// Azure Metadata Service:
pub const AZURE_METADATA_SERVICE_URL: &str =
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F";

pub const INFISICAL_SSL_CERTIFICATE_ENV_NAME: &str = "INFISICAL_SSL_CERTIFICATE";
54 changes: 51 additions & 3 deletions crates/infisical/src/error.rs
Original file line number Diff line number Diff line change
@@ -18,9 +18,48 @@ pub enum Error {
#[error("Something unexpected went wrong.")]
UnknownError,

#[error("Failed to find SSL/TLS certificate")]
SSLCertificateNotFound,

#[error("Invalid SSL/TLS certificate, {}", .message)]
InvalidSSLCertificate { message: String },

#[error("Something went wrong: {}", .message)]
UnknownErrorWithMessage { message: String },

#[error("Failed to get AWS credentials: {}", .message)]
AwsCredentialsError { message: String },

#[error("Failed to build AWS request signer: {}", .message)]
AwsBuildRequestSignerError { message: String },

#[error("Failed to sign AWS request: {}", .message)]
AwsSignRequestError { message: String },

#[error("Failed to get AWS region: {}", .message)]
AwsGetRegionError { message: String },

#[error("Failed to create symmetric key: {}", .message)]
CreateSymmetricKeyError { message: String },

#[error("Failed to authenticate due to missing parameters: {}", .message)]
MissingParametersAuthError { message: String },

#[error("Failed to obtain metadata from Google Cloud")]
GoogleMetadataError,

#[error("Failed to sign JWT from Google Cloud: {}", .message)]
GoogleJwtError { message: String },

#[error("Failed to get token from Google Cloud Platform: {}", .message)]
GoogleTokenError { message: String },

#[error("Authentication parsing failed: {}", .message)]
AuthSanitizationError { message: String },

#[error("No access token was obtained after authentication.")]
NoAccessTokenObtained,

#[error("Failed to encrypt symmetric key: {}", .message)]
EncryptSymmetricKeyError { message: String },

@@ -39,8 +78,8 @@ pub enum Error {
SecretBadRequest { message: String },

// Access token 404 error
#[error("Failed to authenticate, did you provide the correct site URL?")]
NotFoundAccessTokenRequest,
#[error("Failed to authenticate, did you provide the correct site URL?, {}", .message)]
NotFoundAccessTokenRequest { message: String },

// Access token 401 error
#[error("[Failed to authenticate]: Did you provide the correct client ID and secret?")]
@@ -78,7 +117,16 @@ pub async fn api_error_handler(
) -> Result<Error> {
if status == StatusCode::NOT_FOUND {
if is_auth_request {
return Err(Error::NotFoundAccessTokenRequest);
let r = res.json::<BadRequestError>().await;

match r {
Ok(r) => return Err(Error::NotFoundAccessTokenRequest { message: r.message }),
Err(_) => {
return Err(Error::NotFoundAccessTokenRequest {
message: "Unknown error".to_string(),
})
}
}
}

let s = match secret_name {
Loading