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
10 changes: 10 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ The CLI reads auth from the active profile (typically `~/.harness/profiles.yaml`
| `pipeline.spec.yaml` | CI/CD pipelines |
| `core.spec.yaml` | Core resources |

## Security — never put real credentials in code or comments

Do not hardcode into source files, comments, or documentation:
- Account IDs, org IDs, project IDs
- API tokens, OAuth tokens, client secrets
- User emails, UUIDs, or any other PII
- Real hostnames or URLs from live environments (unless they are published public endpoints like `id.harness.io`)

Use placeholder text like `<accountId>`, `<token>`, `<email>` in examples.

## Common pitfalls

- **Binary not updated**: `task build` alone isn't enough — must `cp` to `~/.local/bin/harness`.
Expand Down
12 changes: 12 additions & 0 deletions modules/core/auth/assets/assets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright © 2026 Harness Inc.
// SPDX-License-Identifier: Apache-2.0

package assets

import _ "embed"

//go:embed sso_callback.html
var CallbackHTML string

//go:embed harness-logo.svg
var LogoSVG string
4 changes: 4 additions & 0 deletions modules/core/auth/assets/harness-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
131 changes: 131 additions & 0 deletions modules/core/auth/assets/sso_callback.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Title}}</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #f5f6fa;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #1a1a2e;
}

.card {
background: #ffffff;
border-radius: 16px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 1px 4px rgba(0, 0, 0, 0.04);
padding: 48px 56px;
max-width: 480px;
width: 90%;
text-align: center;
}

.logo {
margin-bottom: 40px;
}

.logo svg {
height: 28px;
width: auto;
}

.icon-wrap {
display: inline-flex;
align-items: center;
justify-content: center;
width: 64px;
height: 64px;
border-radius: 50%;
margin-bottom: 24px;
}

.icon-wrap.success {
background: #e6f9f0;
}

.icon-wrap.error {
background: #fdecea;
}

.icon-wrap svg {
width: 32px;
height: 32px;
}

h1 {
font-size: 22px;
font-weight: 700;
letter-spacing: -0.3px;
margin-bottom: 12px;
}

h1.success { color: #0f7b4d; }
h1.error { color: #c0392b; }

p {
font-size: 15px;
color: #555b6e;
line-height: 1.6;
}

.detail {
margin-top: 8px;
font-size: 13px;
color: #888;
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
background: #f5f6fa;
border-radius: 6px;
padding: 8px 12px;
word-break: break-all;
}

.divider {
border: none;
border-top: 1px solid #eef0f5;
margin: 32px 0;
}

.hint {
font-size: 13px;
color: #aab0c0;
}
</style>
</head>
<body>
<div class="card">
<div class="logo">
{{.LogoSVG}}
</div>

{{if .Success}}
<div class="icon-wrap success">
<svg viewBox="0 0 24 24" fill="none" stroke="#0f7b4d" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"/>
</svg>
</div>
<h1 class="success">Login successful</h1>
<p>You're authenticated. You can close this tab and return to your terminal.</p>
{{else}}
<div class="icon-wrap error">
<svg viewBox="0 0 24 24" fill="none" stroke="#c0392b" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</div>
<h1 class="error">Login failed</h1>
<p>{{.ErrorMessage}}</p>
{{if .ErrorDetail}}<div class="detail">{{.ErrorDetail}}</div>{{end}}
{{end}}

<hr class="divider">
<p class="hint">Harness CLI &mdash; SSO authentication</p>
</div>
</body>
</html>
2 changes: 1 addition & 1 deletion modules/core/auth/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func EnvHandler(ctx *cmdctx.Ctx) error {
}

vars := []struct{ k, v string }{
{hbase.EnvAPIKey, resolved.Token},
{hbase.EnvAPIKey, resolved.PATToken},
{hbase.EnvAccount, resolved.AccountID},
{hbase.EnvAPIURL, resolved.APIUrl},
}
Expand Down
4 changes: 3 additions & 1 deletion modules/core/auth/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ func LoginHandler(ctx *cmdctx.Ctx) error {
existingURL := existingProfile.APIUrl
existingToken := ""
if creds, cerr := auth.LoadCredentials(); cerr == nil {
existingToken = creds[profileName]
if c := creds[profileName]; c != nil {
existingToken = c.Token
}
}
existing = &WizardExisting{APIURL: existingURL, Token: existingToken}
}
Expand Down
Loading
Loading