blob: 50bb84e82753b58953c6ae4ddeea8fd1a17b6810 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:meta/meta.dart';
import '../persistent_tool_state.dart';
import 'io.dart';
import 'net.dart';
import 'platform.dart';
class BotDetector {
BotDetector({
required HttpClientFactory httpClientFactory,
required Platform platform,
required PersistentToolState persistentToolState,
}) :
_platform = platform,
_azureDetector = AzureDetector(
httpClientFactory: httpClientFactory,
),
_persistentToolState = persistentToolState;
final Platform _platform;
final AzureDetector _azureDetector;
final PersistentToolState _persistentToolState;
Future<bool> get isRunningOnBot async {
if (
// Explicitly stated to not be a bot.
_platform.environment['BOT'] == 'false'
// Set by the IDEs to the IDE name, so a strong signal that this is not a bot.
|| _platform.environment.containsKey('FLUTTER_HOST')
// When set, GA logs to a local file (normally for tests) so we don't need to filter.
|| _platform.environment.containsKey('FLUTTER_ANALYTICS_LOG_FILE')
) {
_persistentToolState.setIsRunningOnBot(false);
return false;
}
if (_persistentToolState.isRunningOnBot != null) {
return _persistentToolState.isRunningOnBot!;
}
final bool result = _platform.environment['BOT'] == 'true'
// https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
|| _platform.environment['TRAVIS'] == 'true'
|| _platform.environment['CONTINUOUS_INTEGRATION'] == 'true'
|| _platform.environment.containsKey('CI') // Travis and AppVeyor
// https://www.appveyor.com/docs/environment-variables/
|| _platform.environment.containsKey('APPVEYOR')
// https://cirrus-ci.org/guide/writing-tasks/#environment-variables
|| _platform.environment.containsKey('CIRRUS_CI')
// https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
|| (_platform.environment.containsKey('AWS_REGION') &&
_platform.environment.containsKey('CODEBUILD_INITIATOR'))
// https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables
|| _platform.environment.containsKey('JENKINS_URL')
// https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
|| _platform.environment.containsKey('GITHUB_ACTIONS')
// Properties on Flutter's Chrome Infra bots.
|| _platform.environment['CHROME_HEADLESS'] == '1'
|| _platform.environment.containsKey('BUILDBOT_BUILDERNAME')
|| _platform.environment.containsKey('SWARMING_TASK_ID')
// Property when running on borg.
|| _platform.environment.containsKey('BORG_ALLOC_DIR')
// Property when running on Azure.
|| await _azureDetector.isRunningOnAzure;
_persistentToolState.setIsRunningOnBot(result);
return result;
}
}
// Are we running on Azure?
// https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instance-metadata-service
@visibleForTesting
class AzureDetector {
AzureDetector({
required HttpClientFactory httpClientFactory,
}) : _httpClientFactory = httpClientFactory;
static const String _serviceUrl = 'http://169.254.169.254/metadata/instance';
final HttpClientFactory _httpClientFactory;
bool? _isRunningOnAzure;
Future<bool> get isRunningOnAzure async {
if (_isRunningOnAzure != null) {
return _isRunningOnAzure!;
}
const Duration connectionTimeout = Duration(milliseconds: 250);
const Duration requestTimeout = Duration(seconds: 1);
final HttpClient client = _httpClientFactory()
..connectionTimeout = connectionTimeout;
try {
final HttpClientRequest request = await client.getUrl(
Uri.parse(_serviceUrl),
).timeout(requestTimeout);
request.headers.add('Metadata', true);
await request.close();
} on SocketException {
// If there is an error on the socket, it probably means that we are not
// running on Azure.
return _isRunningOnAzure = false;
} on HttpException {
// If the connection gets set up, but encounters an error condition, it
// still means we're on Azure.
return _isRunningOnAzure = true;
} on TimeoutException {
// The HttpClient connected to a host, but it did not respond in a timely
// fashion. Assume we are not on a bot.
return _isRunningOnAzure = false;
} on OSError {
// The HttpClient might be running in a WSL1 environment.
return _isRunningOnAzure = false;
}
// We got a response. We're running on Azure.
return _isRunningOnAzure = true;
}
}