Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions .github/scripts/check_readme_docs_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ def collect_duplicate_groups(docs_files: Iterable[str]) -> list[DuplicateGroup]:
return groups


def collect_index_parent_groups(docs_files: Iterable[str]) -> dict[str, list[str]]:
by_parent_name: dict[str, list[str]] = {}
for path in docs_files:
normalized = normalize_path(path)
parsed = Path(normalized)
if parsed.name.lower() != "index.md":
continue

parent_name = parsed.parent.name.lower()
by_parent_name.setdefault(parent_name, []).append(normalized)

return by_parent_name


def main() -> int:
args = parse_args()
docs_root = Path(args.docs_root)
Expand All @@ -117,6 +131,7 @@ def main() -> int:
changed_files = load_changed_files(changed_files_json)
docs_files = collect_docs_files(docs_root)
duplicate_groups = collect_duplicate_groups(docs_files)
index_parent_groups = collect_index_parent_groups(docs_files)

duplicate_lookup = {group.basename: group.paths for group in duplicate_groups}

Expand All @@ -133,9 +148,20 @@ def main() -> int:
continue

basename = Path(filename).name.lower()
matching = duplicate_lookup.get(basename)
if matching:
duplicate_violations.append(DuplicateGroup(basename=basename, paths=matching))
if basename == "index.md":
parent_name = Path(filename).parent.name.lower()
matching_index_paths = sorted(index_parent_groups.get(parent_name, []))
if len(matching_index_paths) > 1:
duplicate_violations.append(
DuplicateGroup(
basename=f"index.md (parent: {parent_name})",
paths=matching_index_paths,
)
)
else:
matching = duplicate_lookup.get(basename)
if matching:
duplicate_violations.append(DuplicateGroup(basename=basename, paths=matching))

depth = docs_depth(filename)
if depth > args.max_depth:
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
pnpm-debug.log*

# Python cache
.github/scripts/__pycache__/
2 changes: 1 addition & 1 deletion docs/Integrations & Plugins/plugins-overview/_order.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
- slack-plugin
- spire-plugins
- steampipe-plugin
- teamcity-plugin
- teamcity-plugins
- terraform-provider
- venafi-integration
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- teamcity-plugin
- teamcity-hcv-plugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: TeamCity Plugins
excerpt: ''
deprecated: false
hidden: false
metadata:
title: ''
description: ''
robots: index
next:
description: ''
---
Akeyless supports two TeamCity integration paths.

Choose the plugin that matches your architecture and migration stage.

* [TeamCity Plugin](https://docs.akeyless.io/docs/teamcity-plugin): Native Akeyless TeamCity plugin that connects directly to the Akeyless API.
* The native TeamCity plugin is available in JetBrains Marketplace: [Akeyless Secrets Management](https://plugins.jetbrains.com/plugin/30559-akeyless-secrets-management).
* [TeamCity HCV Plugin](https://docs.akeyless.io/docs/teamcity-hcv-plugin): HashiCorp Vault-compatible integration path through the Akeyless HashiCorp Vault Proxy.

Use the native plugin for new implementations.

Use the HCV plugin if you need compatibility with existing Vault-based TeamCity workflows.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: TeamCity Plugin
title: TeamCity HCV Plugin
excerpt: ''
deprecated: false
hidden: false
Expand All @@ -10,6 +10,10 @@ metadata:
next:
description: ''
---
This page documents the HashiCorp Vault-compatible TeamCity integration path through the Akeyless HashiCorp Vault Proxy.

For the native TeamCity plugin that integrates directly with the Akeyless API, see [TeamCity Plugin](https://docs.akeyless.io/docs/teamcity-plugin).

When performing integration tests and deployments, build scripts need credentials to access external servers and services. The [TeamCity plugin](https://blog.jetbrains.com/teamcity/2017/09/vault/) allows connecting TeamCity to the Akeyless Platform, requesting new credentials when a build starts, passing them to the build script, and revoking them immediately when it finishes.

> ℹ️ **Note:**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: TeamCity Plugin
excerpt: ''
deprecated: false
hidden: false
metadata:
title: ''
description: ''
robots: index
next:
description: ''
---
The TeamCity Plugin integrates TeamCity with Akeyless so your builds can retrieve secrets directly from the Akeyless API without storing sensitive values in TeamCity.

JetBrains Marketplace: [Akeyless Secrets Management](https://plugins.jetbrains.com/plugin/30559-akeyless-secrets-management)

Repository: [akeyless-community/teamcity-akeyless-plugin](https://github.com/akeyless-community/teamcity-akeyless-plugin)

## Features

* Native TeamCity integration for Akeyless secrets retrieval
* Support for static, dynamic, and rotated secrets
* Per-build token flow
* Sensitive value masking in TeamCity logs
* Input validation for API URL and secret path

## Prerequisites

1. TeamCity Server 2024.12 or later.
2. Akeyless authentication method with permissions to read the target secrets.
3. Network connectivity from TeamCity Server to your Akeyless API endpoint.

## Install the Plugin

### Install from TeamCity Marketplace

Marketplace page: [Akeyless Secrets Management](https://plugins.jetbrains.com/plugin/30559-akeyless-secrets-management)

1. In TeamCity, go to **Administration > Plugins**.
2. Select **Browse plugins repository**.
3. Search for `Akeyless Secrets Management`.
4. Install the plugin and restart TeamCity Server.

### Install from ZIP

1. Build or download the plugin ZIP.
2. In TeamCity, go to **Administration > Plugins**.
3. Select **Upload plugin zip**.
4. Upload the ZIP file and restart TeamCity Server.

## Configure a TeamCity Connection

1. Open your TeamCity project.
2. Go to **Connections**.
3. Select **Add Connection**.
4. Choose **Akeyless Secrets Management**.
5. Configure the connection values:

* **Display Name**: Friendly name for the TeamCity connection.
* **API URL**: Akeyless API endpoint (default: `https://api.akeyless.io`).
* **Access ID**: Akeyless Access ID.
* **Authentication Method**: Select one of the supported methods.
* **Credentials**: Provide fields required by the selected method.

## Supported Authentication Methods

* Access Key
* Kubernetes
* AWS IAM
* Azure AD
* GCP
* Certificate (Certificate Data or Certificate File Path)

## Use Secrets in Build Parameters

Use the `akeyless:` prefix for remote secret parameters.

The same parameter structure is used for static, dynamic, and rotated secrets.

Example:

```text
akeyless:/production/database-password
```

Kotlin DSL example:

```kotlin
params {
param("env.DATABASE_PASSWORD", "akeyless:/production/database-password")
param("env.API_KEY", "akeyless:/production/api-key")
}
```

## Troubleshooting

### Authentication fails

* Verify `Access ID` and credential values.
* Verify the authentication method is configured in Akeyless and has the required role permissions.
* Verify the API URL is reachable from TeamCity Server.

### Secret resolution fails

* Verify the secret path is correct and starts with `/`.
* Verify the connection identity has access to the target secret.
* Review TeamCity Server logs for plugin-side errors.

### API URL validation errors

* Use a valid API host URL.
* Use `https` for production endpoints.
* If testing with localhost, use `http://localhost`.
Loading