Skip to content

Commit

Permalink
move hyp settings for local model invocation to env variables (#495)
Browse files Browse the repository at this point in the history
  • Loading branch information
jairad26 authored Oct 23, 2024
1 parent ed839f6 commit e68fb26
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ In previous releases, the name "Hypermode" was used for all three._
- Improve dev first use log messages [#489](https://github.com/hypermodeinc/modus/pull/489)
- Highlight endpoints when running in dev [#490](https://github.com/hypermodeinc/modus/pull/490)
- Fix data race in logging adapter [#491](https://github.com/hypermodeinc/modus/pull/491)
- Move hyp settings for local model invocation to env variables [#495](https://github.com/hypermodeinc/modus/pull/495)

## 2024-10-02 - Version 0.12.7

Expand Down
17 changes: 13 additions & 4 deletions cli/src/commands/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as installer from "../../util/installer.js";
import { getHeader } from "../../custom/header.js";
import { getAppInfo } from "../../util/appinfo.js";
import { isOnline, withSpinner } from "../../util/index.js";
import { readSettingsJson } from "../../util/hypermode.js";
import BuildCommand from "../build/index.js";

export default class DevCommand extends Command {
Expand Down Expand Up @@ -142,12 +143,20 @@ export default class DevCommand extends Command {

await BuildCommand.run([appPath, "--no-logo"]);

// read from settings.json if it exists, load env vars into env
const settings = await readSettingsJson();

const env = {
...process.env,
MODUS_ENV: "dev",
HYP_EMAIL: settings.email,
HYP_JWT: settings.jwt,
HYP_ORG_ID: settings.orgId,
};

const runtime = spawn(runtimePath, ["-appPath", path.join(appPath, "build")], {
stdio: "inherit",
env: {
...process.env,
MODUS_ENV: "dev",
},
env: env,
});
runtime.on("close", (code) => this.exit(code || 1));

Expand Down
45 changes: 45 additions & 0 deletions cli/src/util/hypermode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2024 Hypermode Inc.
* Licensed under the terms of the Apache License, Version 2.0
* See the LICENSE file that accompanied this code for further details.
*
* SPDX-FileCopyrightText: 2024 Hypermode Inc. <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

import * as path from "node:path";
import * as fs from "node:fs";
import * as utils from "./fs.js";
import chalk from "chalk";

function getHypEnvDir(): string {
return path.join(process.env.HOME || "", ".hypermode");
}

function getSettingsFilePath(): string {
return path.join(getHypEnvDir(), "settings.json");
}

type HypSettings = {
email?: string;
jwt?: string;
orgId?: string;
};

export async function readSettingsJson(): Promise<HypSettings> {
const path = getSettingsFilePath();
const content = await utils.readFile(path, "utf-8");

const settings: HypSettings = {};

try {
const jsonContent = JSON.parse(content);
settings.email = jsonContent.HYP_EMAIL;
settings.jwt = jsonContent.HYP_JWT;
settings.orgId = jsonContent.HYP_ORG_ID;
} catch (e) {
console.warn(chalk.yellow("Error reading " + path), e);
}

return settings;
}
44 changes: 43 additions & 1 deletion runtime/secrets/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ import (
"net/http"
"os"
"regexp"
"time"

"github.com/fatih/color"
"github.com/golang-jwt/jwt/v5"
"github.com/hypermodeinc/modus/lib/manifest"
"github.com/hypermodeinc/modus/runtime/logger"
"github.com/hypermodeinc/modus/runtime/utils"
)

var provider secretsProvider
var errLocalAuthFailed = fmt.Errorf("local authentication failed")

type secretsProvider interface {
initialize(ctx context.Context)
Expand Down Expand Up @@ -93,8 +97,24 @@ func ApplyAuthToLocalHypermodeModelRequest(ctx context.Context, connection manif
jwt := os.Getenv("HYP_JWT")
orgId := os.Getenv("HYP_ORG_ID")

warningColor := color.New(color.FgHiYellow, color.Bold)

if jwt == "" || orgId == "" {
return fmt.Errorf("missing HYP_JWT or HYP_ORG_ID environment variables, login to Hypermode using 'hyp login'")
fmt.Println()
warningColor.Println("Warning: Local authentication not found. Please login using `hyp login`")
fmt.Println()
return errLocalAuthFailed
}

isExpired, err := checkJWTExpiration(jwt)
if err != nil {
return err
}
if isExpired {
fmt.Println()
warningColor.Println("Warning: Local authentication expired. Please login using `hyp login`")
fmt.Println()
return errLocalAuthFailed
}

req.Header.Set("Authorization", "Bearer "+jwt)
Expand All @@ -103,6 +123,28 @@ func ApplyAuthToLocalHypermodeModelRequest(ctx context.Context, connection manif
return nil
}

// checkJWTExpiration checks if the JWT has expired based on the 'exp' claim.
func checkJWTExpiration(tokenString string) (bool, error) {
p := jwt.Parser{}
token, _, err := p.ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
return false, fmt.Errorf("failed to parse: %w", err)
}

claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return false, fmt.Errorf("failed to extract claims from JWT")
}

exp, ok := claims["exp"].(float64)
if !ok {
return false, fmt.Errorf("exp claim is missing or not a number")
}

expirationTime := time.Unix(int64(exp), 0)
return time.Now().After(expirationTime), nil
}

// ApplySecretsToString evaluates the given string and replaces any placeholders
// present in the string with their secret values for the given connection.
func ApplySecretsToString(ctx context.Context, connection manifest.ConnectionInfo, str string) (string, error) {
Expand Down

0 comments on commit e68fb26

Please sign in to comment.