Compare commits

...

30 Commits

Author SHA1 Message Date
argo-bot
844f79eb9d Bump version to 2.4.8 2022-07-29 16:47:18 +00:00
argo-bot
ecfa0da491 Bump version to 2.4.8 2022-07-29 16:47:13 +00:00
Alexander Matyushentsev
fac8466e86 fix: extensions is not loading for ConfigMap/Pods (#10010)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-07-28 12:50:06 -07:00
Alexander Matyushentsev
ac34ff23c4 feat: support application level extensions (#9923)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-07-28 12:50:03 -07:00
Alexander Matyushentsev
a85d88d479 feat: support multiple extensions per resource group/kind (#9834)
* feat: support multiple extensions per resource group/kind

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* apply reviewers suggestions

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* apply reviewer notes: stream extension files one by one

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* wrap errors

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* skip symlinks

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2022-07-28 12:50:00 -07:00
dependabot[bot]
40075da70c chore(deps): bump moment from 2.29.3 to 2.29.4 in /ui (#9897)
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

Signed-off-by: CI <michael@crenshaw.dev>
---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-28 15:37:25 -04:00
Snyk bot
779e383f64 fix: upgrade moment from 2.29.2 to 2.29.3 (#9330)
Snyk has created this PR to upgrade moment from 2.29.2 to 2.29.3.

See this package in npm:


See this project in Snyk:
https://app.snyk.io/org/argoproj/project/d2931792-eef9-4d7c-b9d6-c0cbd2bd4dbe?utm_source=github&utm_medium=referral&page=upgrade-pr
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-28 15:36:47 -04:00
Michael Crenshaw
3e523dbab7 fix: skip redirect url validation when it's the base href (#10058) (#10116)
* fix: skip redirect url validation when it's the base href (#10058)

Signed-off-by: CI <michael@crenshaw.dev>

nicer way of doing it

Signed-off-by: CI <michael@crenshaw.dev>

* fix missin arg

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 16:38:05 -04:00
Michael Crenshaw
4df892fecf docs: add OpenSSH breaking change notes (#10104)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 15:26:49 -04:00
Michael Crenshaw
670a1756d7 fix: avoid CVE-2022-28948 (#10093)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 15:03:09 -04:00
Michael Crenshaw
5721f559f0 chore: update parse-url (#10101)
* chore: upgrade parse-url

Signed-off-by: CI <michael@crenshaw.dev>

* edit a generated file, because that's smart

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-27 14:57:06 -04:00
Sahdev Zala
e23178a8d1 docs: add api field example in the appset security doc (#10087)
It seems like most of the work for the mentioned issue below is done
under the PR #9466 but from the issue description, it's probably
worth to mention the example as added here.

Related #9352

Signed-off-by: Sahdev Zala <spzala@us.ibm.com>
2022-07-26 09:15:31 -04:00
Hyeonmin Park
918e5eadf4 fix: Set HOST_ARCH for yarn build from platform (#10018)
Signed-off-by: Hyeonmin Park <hyeonmin.park@kennysoft.kr>
2022-07-25 12:27:29 -04:00
34FathomBelow
55de2b9dab chore: update redis to 7.0.4 avoid CVE-2022-30065 (#10059)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-07-20 17:11:44 -04:00
Ashutosh
c48004f944 docs: add argocd-server grpc metric usage (#10007)
Signed-off-by: Ashutosh <mail.ashutosh8@gmail.com>

Co-authored-by: Ashutosh <mail.ashutosh8@gmail.com>
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-20 14:58:32 -04:00
Michael Crenshaw
f7b6a38041 chore: upgrade Dex to 2.32.0 (#10036) (#10042)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-20 10:45:24 -04:00
Michael Crenshaw
91eb9925ef chore: update redis to avoid CVE-2022-2097 (#10031)
* chore: update redis to avoid CVE-2022-2097

Signed-off-by: CI <michael@crenshaw.dev>

* codegen

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-20 10:38:36 -04:00
34FathomBelow
6190964899 chore: update haproxy to 2.0.29 for redis-ha (#10045)
Signed-off-by: Justin Marquis <34fathombelow@protonmail.com>
2022-07-19 15:05:40 -04:00
argo-bot
81630e6d50 Bump version to 2.4.7 2022-07-18 21:07:45 +00:00
argo-bot
e31fdb6105 Bump version to 2.4.7 2022-07-18 21:07:38 +00:00
Michael Crenshaw
2e194b1087 chore: upgrade parse-url to avoid SNYK-JS-PARSEURL-2936249 (#9826)
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
2022-07-18 14:13:15 -04:00
Jim Wright
cec5799d97 Support files in argocd.argoproj.io/manifest-generate-paths annotation (#9908)
Signed-off-by: Jim Wright <jmwri93@gmail.com>
2022-07-18 11:02:26 -04:00
Michael Crenshaw
7ab2ba361c docs: use quotes to emphasize that ConfigMap value is a string (#9995)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-16 12:21:39 -04:00
Michael Crenshaw
1d5e15c600 fix: terminal websocket write lock to avoid races (#10011)
* fix: protect terminal WriteMessage with a lock

Signed-off-by: CI <michael@crenshaw.dev>

* give write its own lock

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-15 21:43:38 -04:00
Michael Crenshaw
f4f52212ba docs: document directory app include/exclude fields (#9997)
Signed-off-by: CI <michael@crenshaw.dev>
2022-07-15 21:42:58 -04:00
Michael Crenshaw
507c669259 docs: simplify Docker toolchain docs (#9966) (#10006)
* docs: simplify Docker toolchain docs (#9966)

Signed-off-by: CI <michael@crenshaw.dev>

* to be or not to be

Signed-off-by: CI <michael@crenshaw.dev>

* pin dependencies to avoid absurdity

Signed-off-by: CI <michael@crenshaw.dev>
2022-07-15 11:51:48 -04:00
Soumya Ghosh Dastidar
993459aebc fix: updated all a tags to Link tags in app summary (#9777)
* fix: updated all a tags to Link tags

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>

* fix: revert external links to a tags

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>

* fix: linting

Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
2022-07-15 10:17:53 -04:00
rishabh625
3293aa0bb7 fix: e2e test to use func from clusterauth instead creating one with old logic (#9989)
Signed-off-by: rishabh625 <rishabhmishra625@gmail.com>
2022-07-15 09:22:34 -04:00
Hyeonmin Park
aafb6ce0a3 fix: add missing download CLI tool URL response for ppc64le, s390x (#9983)
Signed-off-by: Hyeonmin Park <hyeonmin.park@kennysoft.kr>
2022-07-15 08:55:35 -04:00
Kostis (Codefresh)
d3d490632d docs: supported versions (#9876)
* docs: supported versions

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>

* docs: supported versions feedback

Signed-off-by: Kostis Kapelonis <kostis@codefresh.io>
2022-07-13 11:09:39 -04:00
47 changed files with 539 additions and 207 deletions

View File

@@ -407,7 +407,7 @@ jobs:
run: |
docker pull quay.io/dexidp/dex:v2.25.0
docker pull argoproj/argo-cd-ci-builder:v1.0.0
docker pull redis:7.0.0-alpine
docker pull redis:7.0.4-alpine
- name: Create target directory for binaries in the build-process
run: |
mkdir -p dist

View File

@@ -92,12 +92,13 @@ COPY ["ui/", "."]
ARG ARGO_VERSION=latest
ENV ARGO_VERSION=$ARGO_VERSION
RUN HOST_ARCH='amd64' NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OPTIONS=--max_old_space_size=8192 yarn build
ARG TARGETARCH
RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OPTIONS=--max_old_space_size=8192 yarn build
####################################################################################################
# Argo CD Build stage which performs the actual build of Argo CD binaries
####################################################################################################
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.18 AS argocd-build
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.18 AS argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd

View File

@@ -1 +1 @@
2.4.6
2.4.8

View File

@@ -24,8 +24,7 @@ You will need at least the following things in your toolchain in order to develo
* A Kubernetes cluster. You won't need a fully blown multi-master, multi-node cluster, but you will need something like K3S, Minikube or microk8s. You will also need a working Kubernetes client (`kubectl`) configuration in your development environment. The configuration must reside in `~/.kube/config` and the API server URL must point to the IP address of your local machine (or VM), and **not** to `localhost` or `127.0.0.1` if you are using the virtualized development toolchain (see below)
* You will also need a working Docker runtime environment, to be able to build and run images.
The Docker version must be fairly recent, and support multi-stage builds. You should not work as root. Make your local user a member of the `docker` group to be able to control the Docker service on your machine.
* You will also need a working Docker runtime environment, to be able to build and run images. The Docker version must be 17.05.0 or higher, to support multi-stage builds.
* Obviously, you will need a `git` client for pulling source code and pushing back your changes.

View File

@@ -0,0 +1,64 @@
# UI Extensions
Argo CD web user interface can be extended with additional UI elements. Extensions should be delivered as a javascript file
in the `argocd-server` Pods that are placed in the `/tmp/extensions` directory and starts with `extension` prefix ( matches to `^extension(.*)\.js$` regex ).
```
/tmp/extensions
├── example1
│   └── extension-1.js
└── example2
└── extension-2.js
```
Extensions are loaded during initial page rendering and should register themselves using API exposed in the `extensionsAPI` global variable. (See
corresponding extension type details for additional information).
The extension should provide a React component that is responsible for rendering the UI element. Extension should not bundle the React library.
Instead extension should use the `react` global variable. You can leverage `externals` setting if you are using webpack:
```js
externals: {
react: 'React'
}
```
## Resource Tab Extensions
Resource Tab extensions is an extension that provides an additional tab for the resource sliding panel at the Argo CD Application details page.
The resource tab extension should be registered using the `extensionsAPI.registerResourceExtension` method:
```typescript
registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string)
```
* `component: ExtensionComponent` is a React component that receives the following properties:
* application: Application - Argo CD Application resource;
* resource: State - the kubernetes resource object;
* tree: ApplicationTree - includes list of all resources that comprise the application;
See properties interfaces in [models.ts](https://github.com/argoproj/argo-cd/blob/master/ui/src/app/shared/models.ts)
* `group: string` - the glob expression that matches the group of the resource; note: use globstar (`**`) to match all groups including empty string;
* `kind: string` - the glob expression that matches the kind of the resource;
* `tabTitle: string` - the extension tab title.
* `opts: Object` - additional options:
* `icon: string` - the class name the represents the icon from the [https://fontawesome.com/](https://fontawesome.com/) library (e.g. 'fa-calendar-alt');
Below is an example of a resource tab extension:
```javascript
((window) => {
const component = () => {
return React.createElement( 'div', {}, 'Hello World' );
};
window.extensionsAPI.registerResourceExtension(component, '*', '*', 'Nice extension');
})(window)
```
## Application Tab Extensions
Since the Argo CD Application is a Kubernetes resource, application tabs can be the same as any other resource tab.
Make sure to use 'argoproj.io'/'Application' as group/kind and an extension will be used to render the application-level tab.

View File

@@ -92,6 +92,12 @@ spec:
- code: false
name: foo
value: bar
# Exclude contains a glob pattern to match paths against that should be explicitly excluded from being used during
# manifest generation. This takes precedence over the `include` field.
exclude: string
# Include contains a glob pattern to match paths against that should be explicitly included during manifest
# generation. If this field is set, only matching manifests will be included.
include: string
# plugin specific config
plugin:

View File

@@ -11,8 +11,8 @@ resources of Argo CD itself (like the RBAC ConfigMap).
ApplicationSets can also quickly create an arbitrary number of Applications and just as quickly delete them.
Finally, ApplicationSets can reveal privileged information. For example, the [git generator](./Generators-Git.md) can
read Secrets in the Argo CD namespace and send them to arbitrary URLs as auth headers. (This functionality is intended
for authorizing requests to SCM providers like GitHub, but it could be abused by a malicious user.)
read Secrets in the Argo CD namespace and send them to arbitrary URLs (e.g. URL provided for the `api` field) as auth headers.
(This functionality is intended for authorizing requests to SCM providers like GitHub, but it could be abused by a malicious user.)
For these reasons, **only admins** may be given permission (via Kubernetes RBAC or any other mechanism) to create,
update, or delete ApplicationSets.

View File

@@ -36,8 +36,9 @@ data:
help.chatUrl: "https://mycorp.slack.com/argo-cd"
# the text for getting chat help, defaults to "Chat now!"
help.chatText: "Chat now!"
# The URLs to download additional ArgoCD binaries (besides the Linux amd64 binary included by default)
# The URLs to download additional ArgoCD binaries (besides the Linux with current platform binary included by default)
# for different OS architectures. If provided, additional download buttons will be displayed on the help page.
help.download.linux-amd64: "path-or-url-to-download"
help.download.linux-arm64: "path-or-url-to-download"
help.download.linux-ppc64le: "path-or-url-to-download"
help.download.linux-s390x: "path-or-url-to-download"

View File

@@ -81,3 +81,20 @@ resources:
The Argo CD can be installed using [Helm](https://helm.sh/). The Helm chart is currently community maintained and available at
[argo-helm/charts/argo-cd](https://github.com/argoproj/argo-helm/tree/master/charts/argo-cd).
## Supported versions
Similar to the Kubernetes project, the supported versions of Argo CD at any given point in time are the latest patch releases for the N
and N - 1 minor versions.
These Argo CD versions are supported on the same versions of Kubernetes that are supported by Kubernetes itself (normally the last 3 released versions).
Essentially the Argo CD project follows the same support scheme as Kubernetes but for N, N-1 while Kubernetes supports N, N-1, N-2 versions.
For example if the latest minor version of ArgoCD are 2.4.3 and 2.3.5 while supported Kubernetes versions are 1.24, 1.23 and 1.22 then the following combinations are supported:
* Argo CD 2.4.3 on Kubernetes 1.24
* Argo CD 2.4.3 on Kubernetes 1.23
* Argo CD 2.4.3 on Kubernetes 1.22
* Argo CD 2.3.5 on Kubernetes 1.24
* Argo CD 2.3.5 on Kubernetes 1.23
* Argo CD 2.3.5 on Kubernetes 1.22

View File

@@ -67,8 +67,10 @@ Scraped at the `argocd-server-metrics:8083/metrics` endpoint.
| Metric | Type | Description |
|--------|:----:|-------------|
| `argocd_redis_request_duration` | histogram | Redis requests duration. |
| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application reconciliation. |
| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application
reconciliation. |
| `grpc_server_handled_total` | counter | Total number of RPCs completed on the server, regardless of success or failure. |
| `grpc_server_msg_sent_total` | counter | Total number of gRPC stream messages sent by the server. |
## Repo Server Metrics
Metrics about the Repo Server.
Scraped at the `argocd-repo-server:8084/metrics` endpoint.

View File

@@ -14,3 +14,76 @@ Note that bundled Helm has been upgraded from 3.6.0 to v3.7+. This includes foll
- Experimental OCI support has been rewritten.
More information in the [Helm v3.7.0 release notes](https://github.com/helm/helm/releases/tag/v3.7.0).
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed in 2.2.12
Argo CD 2.2.12 upgraded its base image from Ubuntu 21.10 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).
The signature algorithm is _not_ the same as the algorithm used when generating the key. There is no need to update
keys.
The signature algorithm is negotiated with the SSH server when the connection is being set up. The client offers its
list of accepted signature algorithms, and if the server has a match, the connection proceeds. For most SSH servers on
up-to-date git providers, acceptable algorithms other than `ssh-rsa` should be available.
Before upgrading to Argo CD 2.2.12, check whether your git provider(s) using SSH authentication support algorithms newer
than `rsa-ssh`.
1. Make sure your version of SSH >= 8.9 (the version used by Argo CD). If not, upgrade it before proceeding.
```shell
ssh -V
```
Example output: `OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022`
2. Once you have a recent version of OpenSSH, follow the directions from the [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.7):
> To check whether a server is using the weak ssh-rsa public key
> algorithm, for host authentication, try to connect to it after
> removing the ssh-rsa algorithm from ssh(1)'s allowed list:
>
> ```shell
> ssh -oHostKeyAlgorithms=-ssh-rsa user@host
> ```
>
> If the host key verification fails and no other supported host key
> types are available, the server software on that host should be
> upgraded.
If the server does not support an acceptable version, you will get an error similar to this;
```
$ ssh -oHostKeyAlgorithms=-ssh-rsa vs-ssh.visualstudio.com
Unable to negotiate with 20.42.134.1 port 22: no matching host key type found. Their offer: ssh-rsa
```
This indicates that the server needs to update its supported key signature algorithms, and Argo CD will not connect
to it.
### Workaround
The [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.8) describe a workaround if you cannot change the
server's key signature algorithms configuration.
> Incompatibility is more likely when connecting to older SSH
> implementations that have not been upgraded or have not closely tracked
> improvements in the SSH protocol. For these cases, it may be necessary
> to selectively re-enable RSA/SHA1 to allow connection and/or user
> authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms
> options. For example, the following stanza in ~/.ssh/config will enable
> RSA/SHA1 for host and user authentication for a single destination host:
>
> ```
> Host old-host
> HostkeyAlgorithms +ssh-rsa
> PubkeyAcceptedAlgorithms +ssh-rsa
> ```
>
> We recommend enabling RSA/SHA1 only as a stopgap measure until legacy
> implementations can be upgraded or reconfigured with another key type
> (such as ECDSA or Ed25519).
To apply this to Argo CD, you could create a ConfigMap with the desired ssh config file and then mount it at
`/home/argocd/.ssh/config`.

View File

@@ -46,3 +46,77 @@ Note that bundled Kustomize version has been upgraded from 4.2.0 to 4.4.1.
## Upgraded Helm Version
Note that bundled Helm version has been upgraded from 3.7.1 to 3.8.0.
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed in 2.3.7
Argo CD 2.3.7 upgraded its base image from Ubuntu 21.04 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).
The signature algorithm is _not_ the same as the algorithm used when generating the key. There is no need to update
keys.
The signature algorithm is negotiated with the SSH server when the connection is being set up. The client offers its
list of accepted signature algorithms, and if the server has a match, the connection proceeds. For most SSH servers on
up-to-date git providers, acceptable algorithms other than `ssh-rsa` should be available.
Before upgrading to Argo CD 2.3.7, check whether your git provider(s) using SSH authentication support algorithms newer
than `rsa-ssh`.
1. Make sure your version of SSH >= 8.9 (the version used by Argo CD). If not, upgrade it before proceeding.
```shell
ssh -V
```
Example output: `OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022`
2. Once you have a recent version of OpenSSH, follow the directions from the [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.7):
> To check whether a server is using the weak ssh-rsa public key
> algorithm, for host authentication, try to connect to it after
> removing the ssh-rsa algorithm from ssh(1)'s allowed list:
>
> ```shell
> ssh -oHostKeyAlgorithms=-ssh-rsa user@host
> ```
>
> If the host key verification fails and no other supported host key
> types are available, the server software on that host should be
> upgraded.
If the server does not support an acceptable version, you will get an error similar to this;
```
$ ssh -oHostKeyAlgorithms=-ssh-rsa vs-ssh.visualstudio.com
Unable to negotiate with 20.42.134.1 port 22: no matching host key type found. Their offer: ssh-rsa
```
This indicates that the server needs to update its supported key signature algorithms, and Argo CD will not connect
to it.
### Workaround
The [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.8) describe a workaround if you cannot change the
server's key signature algorithms configuration.
> Incompatibility is more likely when connecting to older SSH
> implementations that have not been upgraded or have not closely tracked
> improvements in the SSH protocol. For these cases, it may be necessary
> to selectively re-enable RSA/SHA1 to allow connection and/or user
> authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms
> options. For example, the following stanza in ~/.ssh/config will enable
> RSA/SHA1 for host and user authentication for a single destination host:
>
> ```
> Host old-host
> HostkeyAlgorithms +ssh-rsa
> PubkeyAcceptedAlgorithms +ssh-rsa
> ```
>
> We recommend enabling RSA/SHA1 only as a stopgap measure until legacy
> implementations can be upgraded or reconfigured with another key type
> (such as ECDSA or Ed25519).
To apply this to Argo CD, you could create a ConfigMap with the desired ssh config file and then mount it at
`/home/argocd/.ssh/config`.

View File

@@ -12,6 +12,8 @@ Helm 2 support was preserved in the Argo CD. We feel that Helm 3 is stable, and
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed
Note: this change was back-ported to 2.3.7 and 2.2.12.
Argo CD 2.4 upgraded its base image from Ubuntu 20.04 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).

View File

@@ -12,7 +12,7 @@ Kubernetes), then the user effectively has the same privileges as that ServiceAc
## Enabling the terminal
1. Set the `exec.enabled` key to `true` on the `argocd-cm` ConfigMap.
1. Set the `exec.enabled` key to `"true"` on the `argocd-cm` ConfigMap.
2. Patch the `argocd-server` Role (if using namespaced Argo) or ClusterRole (if using clustered Argo) to allow `argocd-server`
to exec into pods

View File

@@ -2,4 +2,5 @@ mkdocs==1.2.3
mkdocs-material==7.1.7
markdown_include==0.6.0
pygments==2.7.4
jinja2===3.0.3
jinja2==3.0.3
markdown==3.3.7

3
go.mod
View File

@@ -257,6 +257,9 @@ replace (
github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/improbable-eng/grpc-web => github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a
// Avoid CVE-2022-28948
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
// https://github.com/kubernetes/kubernetes/issues/79384#issuecomment-505627280
k8s.io/api => k8s.io/api v0.23.1
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.1

6
go.sum
View File

@@ -1814,10 +1814,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=

View File

@@ -35,7 +35,7 @@ spec:
runAsNonRoot: true
containers:
- name: dex
image: ghcr.io/dexidp/dex:v2.30.2
image: ghcr.io/dexidp/dex:v2.32.0
imagePullPolicy: Always
command: [/shared/argocd-dex, rundex]
securityContext:

View File

@@ -5,7 +5,7 @@ kind: Kustomization
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.4.6
newTag: v2.4.8
resources:
- ./application-controller
- ./dex

View File

@@ -21,7 +21,7 @@ spec:
serviceAccountName: argocd-redis
containers:
- name: redis
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: Always
args:
- "--save"

View File

@@ -9385,7 +9385,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -9465,7 +9465,7 @@ spec:
- ""
- --appendonly
- "no"
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: Always
name: redis
ports:
@@ -9615,7 +9615,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -9664,7 +9664,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -9851,7 +9851,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -12,4 +12,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.4.6
newTag: v2.4.8

View File

@@ -11,7 +11,7 @@ patchesStrategicMerge:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.4.6
newTag: v2.4.8
resources:
- ../../base/application-controller
- ../../base/applicationset-controller

View File

@@ -770,7 +770,7 @@ spec:
topologyKey: kubernetes.io/hostname
initContainers:
- name: config-init
image: haproxy:2.0.25-alpine
image: haproxy:2.0.29-alpine
imagePullPolicy: IfNotPresent
resources:
{}
@@ -790,7 +790,7 @@ spec:
runAsUser: 1000
containers:
- name: haproxy
image: haproxy:2.0.25-alpine
image: haproxy:2.0.29-alpine
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
@@ -878,7 +878,7 @@ spec:
automountServiceAccountToken: false
initContainers:
- name: config-init
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
resources:
{}
@@ -906,7 +906,7 @@ spec:
containers:
- name: redis
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
command:
- redis-server
@@ -947,7 +947,7 @@ spec:
lifecycle:
{}
- name: sentinel
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
command:
- redis-sentinel

View File

@@ -9,12 +9,12 @@ redis-ha:
haproxy:
enabled: true
image:
tag: 2.0.25-alpine
tag: 2.0.29-alpine
timeout:
server: 6m
client: 6m
checkInterval: 3s
image:
tag: 7.0.0-alpine
tag: 7.0.4-alpine
sentinel:
bind: "0.0.0.0"

View File

@@ -10320,7 +10320,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -10392,7 +10392,7 @@ spec:
- command:
- /shared/argocd-dex
- rundex
image: ghcr.io/dexidp/dex:v2.30.2
image: ghcr.io/dexidp/dex:v2.32.0
imagePullPolicy: Always
name: dex
ports:
@@ -10417,7 +10417,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -10457,7 +10457,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -10526,7 +10526,7 @@ spec:
app.kubernetes.io/name: argocd-redis-ha-haproxy
topologyKey: kubernetes.io/hostname
containers:
- image: haproxy:2.0.25-alpine
- image: haproxy:2.0.29-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -10555,7 +10555,7 @@ spec:
- /readonly/haproxy_init.sh
command:
- sh
image: haproxy:2.0.25-alpine
image: haproxy:2.0.29-alpine
imagePullPolicy: IfNotPresent
name: config-init
volumeMounts:
@@ -10714,7 +10714,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -10763,7 +10763,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -11010,7 +11010,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -11218,7 +11218,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -11299,7 +11299,7 @@ spec:
- /data/conf/redis.conf
command:
- redis-server
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -11337,7 +11337,7 @@ spec:
- /data/conf/sentinel.conf
command:
- redis-sentinel
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -11383,7 +11383,7 @@ spec:
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
- name: SENTINEL_ID_2
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
name: config-init
volumeMounts:

View File

@@ -1244,7 +1244,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1316,7 +1316,7 @@ spec:
- command:
- /shared/argocd-dex
- rundex
image: ghcr.io/dexidp/dex:v2.30.2
image: ghcr.io/dexidp/dex:v2.32.0
imagePullPolicy: Always
name: dex
ports:
@@ -1341,7 +1341,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1381,7 +1381,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1450,7 +1450,7 @@ spec:
app.kubernetes.io/name: argocd-redis-ha-haproxy
topologyKey: kubernetes.io/hostname
containers:
- image: haproxy:2.0.25-alpine
- image: haproxy:2.0.29-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -1479,7 +1479,7 @@ spec:
- /readonly/haproxy_init.sh
command:
- sh
image: haproxy:2.0.25-alpine
image: haproxy:2.0.29-alpine
imagePullPolicy: IfNotPresent
name: config-init
volumeMounts:
@@ -1638,7 +1638,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1687,7 +1687,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1934,7 +1934,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2142,7 +2142,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2223,7 +2223,7 @@ spec:
- /data/conf/redis.conf
command:
- redis-server
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -2261,7 +2261,7 @@ spec:
- /data/conf/sentinel.conf
command:
- redis-sentinel
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -2307,7 +2307,7 @@ spec:
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
- name: SENTINEL_ID_2
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: IfNotPresent
name: config-init
volumeMounts:

View File

@@ -9692,7 +9692,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -9764,7 +9764,7 @@ spec:
- command:
- /shared/argocd-dex
- rundex
image: ghcr.io/dexidp/dex:v2.30.2
image: ghcr.io/dexidp/dex:v2.32.0
imagePullPolicy: Always
name: dex
ports:
@@ -9789,7 +9789,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -9829,7 +9829,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -9904,7 +9904,7 @@ spec:
- ""
- --appendonly
- "no"
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: Always
name: redis
ports:
@@ -10054,7 +10054,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -10103,7 +10103,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -10346,7 +10346,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -10548,7 +10548,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -616,7 +616,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -688,7 +688,7 @@ spec:
- command:
- /shared/argocd-dex
- rundex
image: ghcr.io/dexidp/dex:v2.30.2
image: ghcr.io/dexidp/dex:v2.32.0
imagePullPolicy: Always
name: dex
ports:
@@ -713,7 +713,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -753,7 +753,7 @@ spec:
containers:
- command:
- argocd-notifications
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -828,7 +828,7 @@ spec:
- ""
- --appendonly
- "no"
image: redis:7.0.0-alpine
image: redis:7.0.4-alpine
imagePullPolicy: Always
name: redis
ports:
@@ -978,7 +978,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1027,7 +1027,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1270,7 +1270,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -1472,7 +1472,7 @@ spec:
key: otlp.address
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.4.6
image: quay.io/argoproj/argocd:v2.4.8
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -161,6 +161,7 @@ nav:
- developer-guide/releasing.md
- developer-guide/site.md
- developer-guide/static-code-analysis.md
- developer-guide/ui-extensions.md
- developer-guide/faq.md
- faq.md
- security_considerations.md

View File

@@ -23,11 +23,12 @@ var upgrader = func() websocket.Upgrader {
// terminalSession implements PtyHandler
type terminalSession struct {
wsConn *websocket.Conn
sizeChan chan remotecommand.TerminalSize
doneChan chan struct{}
tty bool
readLock sync.Mutex
wsConn *websocket.Conn
sizeChan chan remotecommand.TerminalSize
doneChan chan struct{}
tty bool
readLock sync.Mutex
writeLock sync.Mutex
}
// newTerminalSession create terminalSession
@@ -95,7 +96,10 @@ func (t *terminalSession) Write(p []byte) (int, error) {
log.Errorf("write parse message err: %v", err)
return 0, err
}
if err := t.wsConn.WriteMessage(websocket.TextMessage, msg); err != nil {
t.writeLock.Lock()
err = t.wsConn.WriteMessage(websocket.TextMessage, msg)
t.writeLock.Unlock()
if err != nil {
log.Errorf("write message err: %v", err)
return 0, err
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"fmt"
goio "io"
"io/fs"
"math"
"net"
@@ -12,6 +13,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"reflect"
"regexp"
go_runtime "runtime"
@@ -100,6 +102,7 @@ import (
"github.com/argoproj/argo-cd/v2/util/healthz"
httputil "github.com/argoproj/argo-cd/v2/util/http"
"github.com/argoproj/argo-cd/v2/util/io"
"github.com/argoproj/argo-cd/v2/util/io/files"
jwtutil "github.com/argoproj/argo-cd/v2/util/jwt"
kubeutil "github.com/argoproj/argo-cd/v2/util/kube"
"github.com/argoproj/argo-cd/v2/util/oidc"
@@ -871,11 +874,11 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
registerDownloadHandlers(mux, "/download")
// Serve extensions
var extensionsApiPath = "/extensions/"
var extensionsSharedPath = "/tmp/extensions/"
extHandler := http.StripPrefix(extensionsApiPath, http.FileServer(http.Dir(extensionsSharedPath)))
mux.HandleFunc(extensionsApiPath, extHandler.ServeHTTP)
mux.HandleFunc("/extensions.js", func(writer http.ResponseWriter, _ *http.Request) {
a.serveExtensions(extensionsSharedPath, writer)
})
// Serve UI static assets
var assetsHandler http.Handler = http.HandlerFunc(a.newStaticAssetsHandler())
@@ -886,6 +889,48 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
return &httpS
}
var extensionsPattern = regexp.MustCompile(`^extension(.*)\.js$`)
func (a *ArgoCDServer) serveExtensions(extensionsSharedPath string, w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/javascript")
err := filepath.Walk(extensionsSharedPath, func(filePath string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("failed to iterate files in '%s': %w", extensionsSharedPath, err)
}
if !files.IsSymlink(info) && !info.IsDir() && extensionsPattern.MatchString(info.Name()) {
processFile := func() error {
if _, err = w.Write([]byte(fmt.Sprintf("// source: %s/%s \n", filePath, info.Name()))); err != nil {
return fmt.Errorf("failed to write to response: %w", err)
}
f, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("failed to open file '%s': %w", filePath, err)
}
defer io.Close(f)
if _, err := goio.Copy(w, f); err != nil {
return fmt.Errorf("failed to copy file '%s': %w", filePath, err)
}
return nil
}
if processFile() != nil {
return fmt.Errorf("failed to serve extension file '%s': %w", filePath, processFile())
}
}
return nil
})
if err != nil && !os.IsNotExist(err) {
log.Errorf("Failed to walk extensions directory: %v", err)
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
}
// registerDexHandlers will register dex HTTP handlers, creating the the OAuth client app
func (a *ArgoCDServer) registerDexHandlers(mux *http.ServeMux) {
if !a.settings.IsSSOConfigured() {

View File

@@ -1,4 +1,4 @@
FROM redis:7.0.0 as redis
FROM redis:7.0.4 as redis
FROM node:12.18.4-buster as node

View File

@@ -14,11 +14,12 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"github.com/argoproj/argo-cd/v2/common"
argocommon "github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
"github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils"
"github.com/argoproj/argo-cd/v2/util/clusterauth"
)
// this implements the "when" part of given/when/then
@@ -61,42 +62,6 @@ func (a *Actions) Then() *Consequences {
return &Consequences{a.context, a}
}
// GetServiceAccountBearerToken will attempt to get the provided service account until it
// exists, iterate the secrets associated with it looking for one of type
// kubernetes.io/service-account-token, and return it's token if found.
// (function based on 'GetServiceAccountBearerToken' from Argo CD's 'clusterauth.go')
func GetServiceAccountBearerToken(clientset kubernetes.Interface, ns string, sa string) (string, error) {
var serviceAccount *corev1.ServiceAccount
var secret *corev1.Secret
var err error
err = wait.Poll(500*time.Millisecond, 30*time.Second, func() (bool, error) {
serviceAccount, err = clientset.CoreV1().ServiceAccounts(ns).Get(context.Background(), sa, metav1.GetOptions{})
if err != nil {
return false, err
}
// Scan all secrets looking for one of the correct type:
for _, oRef := range serviceAccount.Secrets {
var getErr error
secret, err = clientset.CoreV1().Secrets(ns).Get(context.Background(), oRef.Name, metav1.GetOptions{})
if err != nil {
return false, fmt.Errorf("failed to retrieve secret %q: %v", oRef.Name, getErr)
}
if secret.Type == corev1.SecretTypeServiceAccountToken {
return true, nil
}
}
return false, nil
})
if err != nil {
return "", fmt.Errorf("failed to wait for service account secret: %v", err)
}
token, ok := secret.Data["token"]
if !ok {
return "", fmt.Errorf("secret %q for service account %q did not have a token", secret.Name, serviceAccount)
}
return string(token), nil
}
// CreateClusterSecret creates a faux cluster secret, with the given cluster server and cluster name (this cluster
// will not actually be used by the Argo CD controller, but that's not needed for our E2E tests)
func (a *Actions) CreateClusterSecret(secretName string, clusterName string, clusterServer string) *Actions {
@@ -135,7 +100,7 @@ func (a *Actions) CreateClusterSecret(secretName string, clusterName string, clu
if err == nil {
var bearerToken string
bearerToken, err = GetServiceAccountBearerToken(fixtureClient.KubeClientset, utils.ArgoCDNamespace, serviceAccountName)
bearerToken, err = clusterauth.GetServiceAccountBearerToken(fixtureClient.KubeClientset, utils.ArgoCDNamespace, serviceAccountName, common.BearerTokenTimeout)
// bearerToken
secret := &corev1.Secret{

View File

@@ -23,7 +23,7 @@
"json-merge-patch": "^0.2.3",
"lodash-es": "^4.17.21",
"minimatch": "^3.1.2",
"moment": "^2.29.2",
"moment": "^2.29.4",
"monaco-editor": "^0.33.0",
"path": "^0.12.7",
"prop-types": "^15.8.1",

View File

@@ -13,6 +13,7 @@ import {RevisionFormField} from '../revision-form-field/revision-form-field';
import {ComparisonStatusIcon, HealthStatusIcon, syncStatusMessage, urlPattern} from '../utils';
import {ApplicationRetryOptions} from '../application-retry-options/application-retry-options';
import {ApplicationRetryView} from '../application-retry-view/application-retry-view';
import {Link} from 'react-router-dom';
require('./application-summary.scss');
@@ -31,7 +32,7 @@ export const ApplicationSummary = (props: {app: models.Application; updateApp: (
const attributes = [
{
title: 'PROJECT',
view: <a href={'/settings/projects/' + app.spec.project}>{app.spec.project}</a>,
view: <Link to={'/settings/projects/' + app.spec.project}>{app.spec.project}</Link>,
edit: (formApi: FormApi) => (
<DataLoader load={() => services.projects.list('items.metadata.name').then(projs => projs.map(item => item.metadata.name))}>
{projects => <FormField formApi={formApi} field='spec.project' component={FormSelect} componentProps={{options: projects}} />}

View File

@@ -1,5 +1,4 @@
import {DataLoader, Tab, Tabs} from 'argo-ui';
import {useData} from 'argo-ui/v2';
import * as React from 'react';
import {EventsList, YamlEditor} from '../../../shared/components';
import * as models from '../../../shared/models';
@@ -7,7 +6,7 @@ import {ErrorBoundary} from '../../../shared/components/error-boundary/error-bou
import {Context} from '../../../shared/context';
import {Application, ApplicationTree, AppSourceType, Event, RepoAppDetails, ResourceNode, State, SyncStatuses} from '../../../shared/models';
import {services} from '../../../shared/services';
import {ExtensionComponentProps} from '../../../shared/services/extensions-service';
import {ResourceTabExtension} from '../../../shared/services/extensions-service';
import {NodeInfo, SelectNode} from '../application-details/application-details';
import {ApplicationNodeInfo} from '../application-node-info/application-node-info';
import {ApplicationParameters} from '../application-parameters/application-parameters';
@@ -43,15 +42,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
const page = parseInt(new URLSearchParams(appContext.history.location.search).get('page'), 10) || 0;
const untilTimes = (new URLSearchParams(appContext.history.location.search).get('untilTimes') || '').split(',') || [];
const getResourceTabs = (
node: ResourceNode,
state: State,
podState: State,
events: Event[],
ExtensionComponent: React.ComponentType<ExtensionComponentProps>,
tabs: Tab[],
execEnabled: boolean
) => {
const getResourceTabs = (node: ResourceNode, state: State, podState: State, events: Event[], extensionTabs: ResourceTabExtension[], tabs: Tab[], execEnabled: boolean) => {
if (!node || node === undefined) {
return [];
}
@@ -124,15 +115,18 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
]);
}
}
if (ExtensionComponent && state) {
tabs.push({
title: 'More',
key: 'extension',
content: (
<ErrorBoundary message={`Something went wrong with Extension for ${state.kind}`}>
<ExtensionComponent tree={tree} resource={state} />
</ErrorBoundary>
)
if (state) {
extensionTabs.forEach((tabExtensions, i) => {
tabs.push({
title: tabExtensions.title,
key: `extension-${i}`,
content: (
<ErrorBoundary message={`Something went wrong with Extension for ${state.kind}`}>
<tabExtensions.component tree={tree} resource={state} application={application} />
</ErrorBoundary>
),
icon: tabExtensions.icon
});
});
}
return tabs;
@@ -209,19 +203,17 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
content: <ApplicationResourceEvents applicationName={application.metadata.name} />
});
return tabs;
const extensionTabs = services.extensions.getResourceTabs('argoproj.io', 'Application').map((ext, i) => ({
title: ext.title,
key: `extension-${i}`,
content: <ext.component resource={application} tree={tree} application={application} />,
icon: ext.icon
}));
return tabs.concat(extensionTabs);
};
const [extension, , error] = useData(
async () => {
if (selectedNode?.kind && selectedNode?.group) {
return await services.extensions.loadResourceExtension(selectedNode?.group || '', selectedNode?.kind || '');
}
},
null,
null,
[selectedNode]
);
const extensions = selectedNode?.kind ? services.extensions.getResourceTabs(selectedNode?.group || '', selectedNode?.kind) : [];
return (
<div style={{width: '100%', height: '100%'}}>
@@ -302,7 +294,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
data.liveState,
data.podState,
data.events,
error.state ? null : extension?.component,
extensions,
[
{
title: 'SUMMARY',

View File

@@ -38,7 +38,7 @@ export const Help = () => {
<div className='help-box'>
<p>Want to download the CLI tool?</p>
<a href={`download/argocd-linux-${process.env.HOST_ARCH}`} className='user-info-panel-buttons argo-button argo-button--base'>
<i className='fab fa-linux' /> Linux (amd64)
<i className='fab fa-linux' /> Linux ({process.env.HOST_ARCH})
</a>
&nbsp;
{Object.keys(binaryUrls || {}).map(binaryName => {

View File

@@ -9,6 +9,7 @@
<link rel='icon' type='image/png' href='assets/favicon/favicon-32x32.png' sizes='32x32'/>
<link rel='icon' type='image/png' href='assets/favicon/favicon-16x16.png' sizes='16x16'/>
<link href="assets/fonts.css" rel="stylesheet">
</head>
<body>
@@ -20,5 +21,5 @@
</noscript>
<div id="app"></div>
</body>
<script defer src="extensions.js"></script>
</html>

View File

@@ -1,40 +1,62 @@
import * as React from 'react';
import {ApplicationTree, State} from '../models';
import * as minimatch from 'minimatch';
const extensions: {resources: {[key: string]: Extension}} = {resources: {}};
const cache = new Map<string, Promise<Extension>>();
import {Application, ApplicationTree, State} from '../models';
const extensions = {
resourceExtentions: new Array<ResourceTabExtension>()
};
function registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string, opts?: {icon: string}) {
extensions.resourceExtentions.push({component, group, kind, title: tabTitle, icon: opts?.icon});
}
let legacyInitialized = false;
function initLegacyExtensions() {
if (legacyInitialized) {
return;
}
legacyInitialized = true;
const resources = (window as any).extensions.resources;
Object.keys(resources).forEach(key => {
const [group, kind] = key.split('/');
registerResourceExtension(resources[key].component, group, kind, 'More');
});
}
export interface ResourceTabExtension {
title: string;
group: string;
kind: string;
component: ExtensionComponent;
icon?: string;
}
export type ExtensionComponent = React.ComponentType<ExtensionComponentProps>;
export interface Extension {
component: React.ComponentType<ExtensionComponentProps>;
component: ExtensionComponent;
}
export interface ExtensionComponentProps {
resource: State;
tree: ApplicationTree;
application: Application;
}
export class ExtensionsService {
public async loadResourceExtension(group: string, kind: string): Promise<Extension> {
const key = `${group}/${kind}`;
const res =
cache.get(key) ||
new Promise<Extension>((resolve, reject) => {
const script = document.createElement('script');
script.src = `extensions/resources/${group}/${kind}/ui/extensions.js`;
script.onload = () => {
const ext = extensions.resources[key];
if (!ext) {
reject(`Failed to load extension for ${group}/${kind}`);
} else {
resolve(ext);
}
};
script.onerror = reject;
document.body.appendChild(script);
});
cache.set(key, res);
return res;
public getResourceTabs(group: string, kind: string): ResourceTabExtension[] {
initLegacyExtensions();
const items = extensions.resourceExtentions.filter(extension => minimatch(group, extension.group) && minimatch(kind, extension.kind)).slice();
return items.sort((a, b) => a.title.localeCompare(b.title));
}
}
(window as any).extensions = extensions;
((window: any) => {
// deprecated: kept for backwards compatibility
window.extensions = {resources: {}};
window.extensionsAPI = {
registerResourceExtension
};
})(window);

View File

@@ -6338,15 +6338,10 @@ moment-timezone@^0.5.33:
dependencies:
moment ">= 2.9.0"
"moment@>= 2.9.0", moment@^2.24.0, moment@^2.25.3:
version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
moment@^2.29.2:
version "2.29.2"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4"
integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==
"moment@>= 2.9.0", moment@^2.24.0, moment@^2.25.3, moment@^2.29.2, moment@^2.29.4:
version "2.29.4"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
monaco-editor-webpack-plugin@^7.0.0:
version "7.0.1"
@@ -6793,9 +6788,9 @@ parse-json@^5.2.0:
lines-and-columns "^1.1.6"
parse-path@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf"
integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==
version "4.0.4"
resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.4.tgz#4bf424e6b743fb080831f03b536af9fc43f0ffea"
integrity sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==
dependencies:
is-ssh "^1.3.0"
protocols "^1.4.0"
@@ -6803,9 +6798,9 @@ parse-path@^4.0.0:
query-string "^6.13.8"
parse-url@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d"
integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==
version "6.0.5"
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.5.tgz#4acab8982cef1846a0f8675fa686cef24b2f6f9b"
integrity sha512-e35AeLTSIlkw/5GFq70IN7po8fmDUjpDPY1rIK+VubRfsUvBonjQ+PBZG+vWMACnQSmNlvl524IucoDmcioMxA==
dependencies:
is-ssh "^1.3.0"
normalize-url "^6.1.0"

View File

@@ -190,7 +190,7 @@ func (a *ClientApp) verifyAppState(r *http.Request, w http.ResponseWriter, state
redirectURL := a.baseHRef
parts := strings.SplitN(cookieVal, ":", 2)
if len(parts) == 2 && parts[1] != "" {
if !isValidRedirectURL(parts[1], []string{a.settings.URL}) {
if !isValidRedirectURL(parts[1], []string{a.settings.URL, a.baseHRef}) {
sanitizedUrl := parts[1]
if len(sanitizedUrl) > 100 {
sanitizedUrl = sanitizedUrl[:100]

View File

@@ -192,6 +192,52 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL),
})
}
func Test_Login_Flow(t *testing.T) {
// Show that SSO login works when no redirect URL is provided, and we fall back to the configured base href for the
// Argo CD instance.
oidcTestServer := test.GetOIDCTestServer(t)
t.Cleanup(oidcTestServer.Close)
cdSettings := &settings.ArgoCDSettings{
URL: "https://argocd.example.com",
OIDCConfigRAW: fmt.Sprintf(`
name: Test
issuer: %s
clientID: xxx
clientSecret: yyy
requestedScopes: ["oidc"]`, oidcTestServer.URL),
OIDCTLSInsecureSkipVerify: true,
}
// The base href (the last argument for NewClientApp) is what HandleLogin will fall back to when no explicit
// redirect URL is given.
app, err := NewClientApp(cdSettings, "", "/")
require.NoError(t, err)
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "https://argocd.example.com/auth/login", nil)
app.HandleLogin(w, req)
redirectUrl, err := w.Result().Location()
require.NoError(t, err)
state := redirectUrl.Query()["state"]
req = httptest.NewRequest("GET", fmt.Sprintf("https://argocd.example.com/auth/callback?state=%s&code=abc", state), nil)
for _, cookie := range w.Result().Cookies() {
req.AddCookie(cookie)
}
w = httptest.NewRecorder()
app.HandleCallback(w, req)
assert.NotContains(t, w.Body.String(), InvalidRedirectURLError.Error())
}
func TestClientApp_HandleCallback(t *testing.T) {
oidcTestServer := test.GetOIDCTestServer(t)
t.Cleanup(oidcTestServer.Close)

View File

@@ -1239,7 +1239,7 @@ func (mgr *SettingsManager) ensureSynced(forceResync bool) error {
func getDownloadBinaryUrlsFromConfigMap(argoCDCM *apiv1.ConfigMap) map[string]string {
binaryUrls := map[string]string{}
for _, archType := range []string{"darwin-amd64", "darwin-arm64", "windows-amd64", "linux-arm64", "linux-amd64"} {
for _, archType := range []string{"darwin-amd64", "darwin-arm64", "windows-amd64", "linux-amd64", "linux-arm64", "linux-ppc64le", "linux-s390x"} {
if val, ok := argoCDCM.Data[settingsBinaryUrlsKey+"."+archType]; ok {
binaryUrls[archType] = val
}

View File

@@ -668,11 +668,12 @@ func TestSettingsManager_GetHelp(t *testing.T) {
t.Run("GetBinaryUrls", func(t *testing.T) {
_, settingsManager := fixtures(map[string]string{
"help.download.darwin-amd64": "amd64-path",
"help.download.linux-s390x": "s390x-path",
"help.download.unsupported": "nowhere",
})
h, err := settingsManager.GetHelp()
assert.NoError(t, err)
assert.Equal(t, map[string]string{"darwin-amd64": "amd64-path"}, h.BinaryURLs)
assert.Equal(t, map[string]string{"darwin-amd64": "amd64-path", "linux-s390x": "s390x-path"}, h.BinaryURLs)
})
}
@@ -986,6 +987,13 @@ func TestDownloadArgoCDBinaryUrls(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "some-url", argoCDCM.Data["help.download.darwin-amd64"])
_, settingsManager = fixtures(map[string]string{
"help.download.linux-s390x": "some-url",
})
argoCDCM, err = settingsManager.getConfigMap()
assert.NoError(t, err)
assert.Equal(t, "some-url", argoCDCM.Data["help.download.linux-s390x"])
_, settingsManager = fixtures(map[string]string{
"help.download.unsupported": "some-url",
})

View File

@@ -331,8 +331,13 @@ func appFilesHaveChanged(app *v1alpha1.Application, changedFiles []string) bool
f = ensureAbsPath(f)
for _, item := range refreshPaths {
item = ensureAbsPath(item)
if _, err := security.EnforceToCurrentRoot(item, f); err == nil {
changed := false
if f == item {
changed = true
} else if _, err := security.EnforceToCurrentRoot(item, f); err == nil {
changed = true
}
if changed {
log.WithField("application", app.Name).Debugf("Application uses files that have changed")
return true
}

View File

@@ -219,6 +219,12 @@ func Test_getAppRefreshPrefix(t *testing.T) {
{"absolute path - not matching", getApp("/source/path1", "source/path"), []string{"source/path/my-deployment.yaml"}, false},
{"two relative paths - matching", getApp(".;../shared", "my-app"), []string{"shared/my-deployment.yaml"}, true},
{"two relative paths - not matching", getApp(".;../shared", "my-app"), []string{"README.md"}, false},
{"file relative path - matching", getApp("./my-deployment.yaml", "source/path"), []string{"source/path/my-deployment.yaml"}, true},
{"file relative path - not matching", getApp("./my-deployment.yaml", "source/path"), []string{"README.md"}, false},
{"file absolute path - matching", getApp("/source/path/my-deployment.yaml", "source/path"), []string{"source/path/my-deployment.yaml"}, true},
{"file absolute path - not matching", getApp("/source/path1/README.md", "source/path"), []string{"source/path/my-deployment.yaml"}, false},
{"file two relative paths - matching", getApp("./README.md;../shared/my-deployment.yaml", "my-app"), []string{"shared/my-deployment.yaml"}, true},
{"file two relative paths - not matching", getApp(".README.md;../shared/my-deployment.yaml", "my-app"), []string{"kustomization.yaml"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {