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
9 changes: 9 additions & 0 deletions base/cvd/cuttlefish/common/libs/utils/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,15 @@ cf_cc_library(
],
)

cf_cc_library(
name = "is_google_corp",
srcs = ["is_google_corp.cpp"],
hdrs = ["is_google_corp.h"],
deps = [
"//cuttlefish/common/libs/utils:files",
],
)

cf_cc_library(
name = "json",
srcs = ["json.cpp"],
Expand Down
33 changes: 33 additions & 0 deletions base/cvd/cuttlefish/common/libs/utils/is_google_corp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cuttlefish/common/libs/utils/is_google_corp.h"

#include <string>
#include <string_view>

#include "cuttlefish/common/libs/utils/files.h"

namespace cuttlefish {
namespace {

constexpr std::string_view kGoogleCorpDir = "/google";

} // namespace

bool IsGoogleCorp() { return DirectoryExists(std::string(kGoogleCorpDir)); }

} // namespace cuttlefish
23 changes: 23 additions & 0 deletions base/cvd/cuttlefish/common/libs/utils/is_google_corp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

namespace cuttlefish {

bool IsGoogleCorp();

} // namespace cuttlefish
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ cf_cc_library(
"//cuttlefish/host/commands/cvd/cli:command_request",
"//cuttlefish/host/commands/cvd/cli:types",
"//cuttlefish/host/commands/cvd/cli/commands:command_handler",
"//cuttlefish/host/commands/cvd/fetch:auto_login",
"//cuttlefish/host/commands/cvd/fetch:build_api_flags",
"//cuttlefish/host/commands/cvd/fetch:fetch_cvd",
"//cuttlefish/host/commands/cvd/fetch:fetch_cvd_parser",
"//cuttlefish/host/commands/cvd/utils",
Expand Down Expand Up @@ -206,8 +208,8 @@ cf_cc_library(
hdrs = ["login.h"],
deps = [
"//cuttlefish/common/libs/utils:environment",
"//cuttlefish/common/libs/utils:files",
"//cuttlefish/common/libs/utils:flag_parser",
"//cuttlefish/common/libs/utils:is_google_corp",
"//cuttlefish/host/commands/cvd/cli:command_request",
"//cuttlefish/host/commands/cvd/cli:types",
"//cuttlefish/host/commands/cvd/cli/commands:command_handler",
Expand Down
63 changes: 48 additions & 15 deletions base/cvd/cuttlefish/host/commands/cvd/cli/commands/fetch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "cuttlefish/host/commands/cvd/cli/command_request.h"
#include "cuttlefish/host/commands/cvd/cli/commands/command_handler.h"
#include "cuttlefish/host/commands/cvd/cli/types.h"
#include "cuttlefish/host/commands/cvd/fetch/auto_login.h"
#include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h"
#include "cuttlefish/host/commands/cvd/fetch/fetch_cvd.h"
#include "cuttlefish/host/commands/cvd/fetch/fetch_cvd_parser.h"
#include "cuttlefish/host/commands/cvd/utils/common.h"
Expand All @@ -50,32 +52,63 @@ class CvdFetchCommandHandler : public CvdCommandHandler {
Result<std::string> DetailedHelp(const CommandRequest& request) const override;
};

Result<void> RunAutoLogin(const BuildApiFlags& build_api_flags) {
if (!CF_EXPECT(ShouldAutoLogin(build_api_flags))) {
return {};
}
LOG(INFO) << "\nNo credentials detected on corp, running credential "
"workflow. Please follow prompts.\n";
if (!CanRunAutoLogin()) {
LOG(INFO) << "\nUnable to detect necessary files for credentialing. Do "
"you need to run `gcert`?\n";
return {};
}

CF_EXPECT(RunLogin());
LOG(INFO)
<< "\nLogin successful. This will persist across future executions.";
return {};
}

Result<void> RunCacheCleanup(const BuildApiFlags& build_api_flags) {
if (!build_api_flags.enable_caching) {
return {};
}

VLOG(0) << "Running automatic cache cleanup";
const std::string cache_directory = PerUserCacheDir();
const PruneResult prune_result =
CF_EXPECTF(PruneCache(cache_directory, build_api_flags.max_cache_size_gb),
"Error pruning cache at {} to {}GB", cache_directory,
build_api_flags.max_cache_size_gb);
if (prune_result.before > prune_result.after) {
LOG(INFO) << fmt::format(
"Cache at \"{}\" pruned from ~{}GB to ~{}GB of {}GB max size",
cache_directory, prune_result.before, prune_result.after,
build_api_flags.max_cache_size_gb);
}
return {};
}

Result<void> CvdFetchCommandHandler::Handle(const CommandRequest& request) {
CF_EXPECT(CanHandle(request));

std::vector<std::string> args = request.SubcommandArguments();
const FetchFlags flags = CF_EXPECT(FetchFlags::Parse(args));
CF_EXPECT(EnsureDirectoryExists(flags.target_directory));
GatherFetchStartMetrics(flags);
Result<void> ensure_credentials_result = RunAutoLogin(flags.build_api_flags);
if (!ensure_credentials_result.ok()) {
LOG(INFO) << "Auto-login failed with the following error:\n"
<< ensure_credentials_result.error() << "\n";
LOG(INFO) << "Still running the fetch operation.";
}

GatherFetchStartMetrics(flags);
std::string log_file = GetFetchLogsFileName(flags.target_directory);
ScopedLogger logger(SeverityTarget::FromFile(log_file), "");

Result<FetchResult> result = FetchCvdMain(flags);
if (flags.build_api_flags.enable_caching) {
VLOG(0) << "Running automatic cache cleanup";
const std::string cache_directory = PerUserCacheDir();
const PruneResult prune_result = CF_EXPECTF(
PruneCache(cache_directory, flags.build_api_flags.max_cache_size_gb),
"Error pruning cache at {} to {}GB", cache_directory,
flags.build_api_flags.max_cache_size_gb);
if (prune_result.before > prune_result.after) {
LOG(INFO) << fmt::format(
"Cache at \"{}\" pruned from ~{}GB to ~{}GB of {}GB max size",
cache_directory, prune_result.before, prune_result.after,
flags.build_api_flags.max_cache_size_gb);
}
}
CF_EXPECT(RunCacheCleanup(flags.build_api_flags));

if (result.ok()) {
GatherFetchCompleteMetrics(flags.target_directory, *result);
Expand Down
4 changes: 2 additions & 2 deletions base/cvd/cuttlefish/host/commands/cvd/cli/commands/login.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
#include <vector>

#include "cuttlefish/common/libs/utils/environment.h"
#include "cuttlefish/common/libs/utils/files.h"
#include "cuttlefish/common/libs/utils/flag_parser.h"
#include "cuttlefish/common/libs/utils/is_google_corp.h"
#include "cuttlefish/host/commands/cvd/cli/command_request.h"
#include "cuttlefish/host/commands/cvd/cli/commands/command_handler.h"
#include "cuttlefish/host/commands/cvd/cli/types.h"
Expand Down Expand Up @@ -95,7 +95,7 @@ class CvdLoginCommand : public CvdCommandHandler {

Result<std::string> DetailedHelp(const CommandRequest& request) const override {
std::string google_appendix;
if (DirectoryExists("/google")) {
if (IsGoogleCorp()) {
google_appendix =
"\nIf running on corp, use the wrapper script in "
"google3/cloud/android/login";
Expand Down
21 changes: 21 additions & 0 deletions base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ package(
default_visibility = ["//:android_cuttlefish"],
)

cf_cc_library(
name = "auto_login",
srcs = [
"auto_login.cc",
],
hdrs = [
"auto_login.h",
],
deps = [
"//cuttlefish/common/libs/utils:files",
"//cuttlefish/common/libs/utils:is_google_corp",
"//cuttlefish/common/libs/utils:subprocess",
"//cuttlefish/common/libs/utils:subprocess_managed_stdio",
"//cuttlefish/host/commands/cvd/fetch:build_api_credentials",
"//cuttlefish/host/commands/cvd/fetch:build_api_flags",
"//cuttlefish/host/libs/web:oauth2_consent",
"//cuttlefish/result",
],
)

cf_cc_library(
name = "build_api_credentials",
srcs = [
Expand All @@ -16,6 +36,7 @@ cf_cc_library(
"build_api_credentials.h",
],
deps = [
"//cuttlefish/common/libs/utils:environment",
"//cuttlefish/common/libs/utils:files",
"//cuttlefish/common/libs/utils:json",
"//cuttlefish/host/commands/cvd/fetch:build_api_flags",
Expand Down
70 changes: 70 additions & 0 deletions base/cvd/cuttlefish/host/commands/cvd/fetch/auto_login.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// Copyright (C) 2026 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cuttlefish/host/commands/cvd/fetch/auto_login.h"

#include <string>
#include <string_view>

#include "cuttlefish/common/libs/utils/files.h"
#include "cuttlefish/common/libs/utils/is_google_corp.h"
#include "cuttlefish/common/libs/utils/subprocess.h"
#include "cuttlefish/common/libs/utils/subprocess_managed_stdio.h"
#include "cuttlefish/host/commands/cvd/fetch/build_api_credentials.h"
#include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h"
#include "cuttlefish/host/libs/web/oauth2_consent.h"
#include "cuttlefish/result/result.h"

namespace cuttlefish {
namespace {

constexpr std::string_view kWrapperFilepath =
"/google/src/head/depot/google3/cloud/android/login/login.sh";

bool IsCredentialFlagPresent(const BuildApiFlags& flags) {
return !flags.credential_source.empty() ||
flags.credential_flags.use_gce_metadata ||
!flags.credential_flags.credential_filepath.empty() ||
!flags.credential_flags.service_account_filepath.empty();
}

Result<bool> IsCredentialFilePresent() {
return FileExists(GetAcloudOauthFilepath()) ||
!CF_EXPECT(GetCvdCredentialFilepaths()).empty();
}

} // namespace

Result<bool> ShouldAutoLogin(const BuildApiFlags& flags) {
return !IsCredentialFlagPresent(flags) &&
!CF_EXPECT(IsCredentialFilePresent(),
"Failed searching for credential files.") &&
IsGoogleCorp();
}

bool CanRunAutoLogin() { return FileExists(std::string(kWrapperFilepath)); }

Result<void> RunLogin() {
Command login_command =
Command(std::string(kWrapperFilepath)).AddParameter("--ssh");
std::string stderr;
const int exit_code =
RunWithManagedStdio(std::move(login_command), nullptr, nullptr, &stderr);
CF_EXPECTF(exit_code == 0, "Failure to automatically credential:\n{}",
stderr);
return {};
}

} // namespace cuttlefish
29 changes: 29 additions & 0 deletions base/cvd/cuttlefish/host/commands/cvd/fetch/auto_login.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Copyright (C) 2026 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h"
#include "cuttlefish/result/result.h"

namespace cuttlefish {

Result<bool> ShouldAutoLogin(const BuildApiFlags&);

bool CanRunAutoLogin();

Result<void> RunLogin();

} // namespace cuttlefish
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "absl/log/log.h"

#include "cuttlefish/common/libs/utils/environment.h"
#include "cuttlefish/common/libs/utils/files.h"
#include "cuttlefish/common/libs/utils/json.h"
#include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h"
Expand Down Expand Up @@ -147,4 +148,8 @@ Result<std::unique_ptr<CredentialSource>> GetCredentialSourceFromFlags(
flags.credential_flags.service_account_filepath));
}

std::string GetAcloudOauthFilepath() {
return StringFromEnv("HOME", ".") + "/.acloud_oauth2.dat";
}

} // namespace cuttlefish
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ Result<std::unique_ptr<CredentialSource>> GetCredentialSourceFromFlags(
HttpClient& http_client, const BuildApiFlags& flags,
const std::string& oauth_filepath);

std::string GetAcloudOauthFilepath();

} // namespace cuttlefish
7 changes: 2 additions & 5 deletions base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,11 @@ Result<Downloaders> Downloaders::Create(const BuildApiFlags& flags,
Result<std::unique_ptr<CredentialSource>> cvd_creds =
CredentialForScopes(*impl->curl_, scopes);

std::string oauth_filepath =
StringFromEnv("HOME", ".") + "/.acloud_oauth2.dat";

impl->android_creds_ =
cvd_creds.ok() && cvd_creds->get()
? std::move(*cvd_creds)
: CF_EXPECT(GetCredentialSourceFromFlags(*impl->retrying_http_client_,
flags, oauth_filepath));
: CF_EXPECT(GetCredentialSourceFromFlags(
*impl->retrying_http_client_, flags, GetAcloudOauthFilepath()));

impl->android_build_url_ = std::make_unique<AndroidBuildUrl>(
flags.api_base_url, flags.api_key, flags.project_id);
Expand Down
Loading